package com.toro.gdd2011.slidepuzzle;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.lang.Thread.State;

public class SlidePuzzle {
	private class PuzzleData {
		public int mWidth;
		public int mHeight;
		public int mData[][];
		public int mZeroX;
		public int mZeroY;
	};
	
	private class Position {
		public int mX;
		public int mY;
	}
	
	private static final int WALL_DATA = 36;
	private static final int SPACE_DATA = 0;
	private int mLx, mRx, mUx, mDx;
	private int mPuzzleCount;
	private PuzzleData mPuzzleData[];
	private String mResult[];
	private String mAnswer[];
	private int mCounter;
	
	public static void main(String[] args) {
		new SlidePuzzle().run();
	}

	private void run() {
		// ファイルの読み込み
		readFile();
		// 中間データ、解答データ等の初期化
		init();
		// 解く
		solveSlidePuzzle();
		// 解いたデータから解答データの作成
		createAnswerData();
		// ファイルに書き出し
		writeFile();
	}
	
	private void readFile() {
		try{
			BufferedReader br = new BufferedReader(new FileReader("./input.dat"));
			String s;
			String[] line;
			// 使用できるL,R,U,Dの数を読み込み
			s = br.readLine();
			line = s.split(" ");
			mLx = Integer.valueOf(line[0]);
			mRx = Integer.valueOf(line[1]);
			mUx = Integer.valueOf(line[2]);
			mDx = Integer.valueOf(line[3]);
			// すべてのパズルの数を読み込み
			mPuzzleCount = Integer.valueOf(br.readLine());
			// パズルを読み込む
			mPuzzleData = new PuzzleData[mPuzzleCount];
			for(int i = 0; i < mPuzzleCount; i++) {
				s = br.readLine();
				line = s.split(",");
				mPuzzleData[i] = getPuzzleData(line[0], line[1], line[2]);
			}
			// 読み込み終了
			br.close();
		}catch(Exception e){
			e.printStackTrace();
		}
	}

	private PuzzleData getPuzzleData(String strWidth, String strHeight, String strBord) {
		PuzzleData puzzleData = new PuzzleData();
		puzzleData.mWidth = Integer.valueOf(strWidth);
		puzzleData.mHeight = Integer.valueOf(strHeight);
		puzzleData.mData = new int[puzzleData.mHeight][puzzleData.mWidth];
		for(int i = 0; i < puzzleData.mHeight; i++) {
			for(int j = 0; j < puzzleData.mWidth; j++) {
				char ch = strBord.charAt(i * puzzleData.mWidth + j);
				if((puzzleData.mData[i][j] = getBordIntData(ch)) == SPACE_DATA) {
					puzzleData.mZeroX = j;
					puzzleData.mZeroY = i;
				}
			}
		}
		return puzzleData;
	}

	private int getBordIntData(char ch) {
		int ret = -1;
		if(ch >= '0' && ch <= '9') {
			ret = ch - '0';					// 0-9
		} else if(ch >= 'A' && ch <= 'Z') {
			ret = ch - 'A' + 10;			// 10-35
		} else if(ch == '=') {				// 壁
			ret = WALL_DATA;
		} 
		return ret;
	}

	private void init() {
		mCounter = -1;
		// 解いた解答データ格納用
		mResult = new String[mPuzzleCount];
		for(int i = 0; i < mPuzzleCount; i++) {
			mResult[i] = new String("");
		}
		// 結果出力用
		mAnswer = new String[mPuzzleCount];
		for(int i = 0; i < mPuzzleCount; i++) {
			mAnswer[i] = new String("");
		}
		
	}
	
	private void createAnswerData() {
		// とりあえず全部出力
		for(int i = 0; i < mPuzzleCount; i++) {
			String tmp = mResult[i];
			// 回答の圧縮
			do{
				mAnswer[i] = tmp;
				tmp = tmp.replace("LR", "");
				tmp = tmp.replace("RL", "");
				tmp = tmp.replace("UD", "");
				tmp = tmp.replace("DU", "");
			} while(!tmp.equals(mAnswer[i]));
		}
	}
	
	private void writeFile() {
		int tmp = 0;
		try{
			BufferedWriter bw = new BufferedWriter(new FileWriter("./output.dat"));
			for(int i = 0; i < mPuzzleCount; i++) {
				bw.write(mAnswer[i] + "\n");
				if(!mAnswer[i].equals("")) {
					tmp++;
				}
			}
			bw.close();
		}catch(Exception e){
			e.printStackTrace();
		}
		System.out.println(tmp);
	}
	
	private void solveSlidePuzzle() {
		SolveSlidePuzzleThread thread1 = new SolveSlidePuzzleThread(this, mPuzzleCount, mPuzzleData, mResult);
		SolveSlidePuzzleThread thread2 = new SolveSlidePuzzleThread(this, mPuzzleCount, mPuzzleData, mResult);
		SolveSlidePuzzleThread thread3 = new SolveSlidePuzzleThread(this, mPuzzleCount, mPuzzleData, mResult);
		SolveSlidePuzzleThread thread4 = new SolveSlidePuzzleThread(this, mPuzzleCount, mPuzzleData, mResult);
		thread1.start();
		thread2.start();
		thread3.start();
		thread4.start();
		try {
			thread1.join();
			if(thread2.getState() != State.TERMINATED) {
				thread2.join();
			}
			if(thread3.getState() != State.TERMINATED) {
				thread3.join();
			}
			if(thread4.getState() != State.TERMINATED) {
				thread4.join();
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
	}
	
	synchronized public int getNextPuzzleNumber() {
		mCounter++;
		return mCounter;
	}
	
	private class SolveSlidePuzzleThread extends Thread {
		private static final int WALL_DATA = 36;
		private static final int SPACE_DATA = 0;
		private static final int OPE_N = 0;
		private static final int OPE_L = 1;
		private static final int OPE_R = 2;
		private static final int OPE_U = 3;
		private static final int OPE_D = 4;
		private static final int MAX_SEARCH_COUNT = 12;
		private static final int MAX_SEARCH_COUNT_3 = 15;
		
		private int mPuzzleCount;
		private PuzzleData mPuzzleData[];
		private String mResult[];
		private SlidePuzzle mParent;
		
		public SolveSlidePuzzleThread(SlidePuzzle parent, int puzzleCount, PuzzleData puzzleData[], String result[]) {
			mParent = parent;
			mPuzzleCount = puzzleCount;
			mPuzzleData = puzzleData;
			mResult = result;
		}
		
		public void run(){
			while(true) {
				int i = mParent.getNextPuzzleNumber();
				if(i >= mPuzzleCount) {
					break;
				}
				System.out.println(i);
				boolean isWithWall = isPussleWithWall(i, 0, 0);
				switch(mPuzzleData[i].mWidth) {
				case 3:
					switch(mPuzzleData[i].mHeight) {
					case 3:
						if(!isWithWall) {
							// 3x3(壁なし)を解く
							solve3x3(i, 0, 0);
						} else {
							// 3x3(壁あり)を解く
							if(!solve3x3withWall(i, 0, 0)){
								mResult[i] = "";
							}
						}
						break;
					case 4:
						if(!isWithWall) {
							// 3x4(壁なし)を解く
							solve3x4(i, 0, 0);
						} else {
							// 3x4(壁あり)を解く
							if(!solve3x4withWall(i, 0, 0)){
								mResult[i] = "";
							}
						}
						break;
					case 5:
						if(!isWithWall) {
							// 3x5(壁なし)を解く
							solve3x5(i, 0, 0);
						} else {
							// 3x5(壁あり)を解く
							if(!solve3x5withWall(i, 0, 0)) {
								mResult[i] = "";
							}
						}
						break;
					case 6:
						if(!isWithWall) {
							// 3x6(壁なし)を解く
							solve3x6(i, 0, 0);
						} else {
							// 3x6(壁あり)を解く
							if(!solve3x6withWall(i, 0, 0)) {
								mResult[i] = "";
							}
						}
						break;
					default:
						break;
					}
					break;
				case 4:
					switch(mPuzzleData[i].mHeight) {
					case 3:
						if(!isWithWall) {
							// 4x3(壁なし)を解く
							solve4x3(i, 0, 0);
						} else {
							// 4x3(壁あり)を解く
							if(!solve4x3withWall(i, 0, 0)) {
								mResult[i] = "";
							}
						}
						break;
					case 4:
						if(!isWithWall) {
							// 4x4(壁なし)を解く
							solve4x4(i, 0, 0);
						} else {
							// 4x4(壁あり)を解く
							if(!solve4x4withWall(i, 0, 0)) {
								mResult[i] = "";
							}
						}
						break;
					case 5:
						if(!isWithWall) {
							// 4x5(壁なし)を解く
							solve4x5(i, 0, 0);
						} else {
							// 4x5(壁あり)を解く
							if(!solve4x5withWall(i, 0, 0)) {
								mResult[i] = "";
							}
						}
						break;
					case 6:
						if(!isWithWall) {
							// 4x6(壁なし)を解く
							solve4x6(i, 0, 0);
						} else {
							// 4x6(壁あり)を解く
							if(!solve4x6withWall(i, 0, 0)) {
								mResult[i] = "";
							}
						}
						break;
					default:
						break;
					}
					break;
				case 5:
					switch(mPuzzleData[i].mHeight) {
					case 3:
						if(!isWithWall) {
							// 5x3(壁なし)を解く
							solve5x3(i, 0, 0);
						} else {
							// 5x3(壁あり)を解く
							if(!solve5x3withWall(i, 0, 0)) {
								mResult[i] = "";
							}
						}
						break;
					case 4:
						if(!isWithWall) {
							// 5x4(壁なし)を解く
							solve5x4(i, 0, 0);
						} else {
							// 5x4(壁あり)を解く
							if(!solve5x4withWall(i, 0, 0)) {
								mResult[i] = "";
							}
						}
						break;
					case 5:
						if(!isWithWall) {
							// 5x5(壁なし)を解く
							solve5x5(i, 0, 0);
						} else {
							// 5x5(壁あり)を解く
							if(!solve5x5withWall(i, 0, 0)) {
								mResult[i] = "";
							}
						}
						break;
					case 6:
						if(!isWithWall) {
							// 5x6(壁なし)を解く
							solve5x6(i, 0, 0);
						} else {
							// 5x6(壁あり)を解く
							if(!solve5x6withWall(i, 0, 0)) {
								mResult[i] = "";
							}
						}
						break;
					default:
						break;
					}
					break;
				case 6:
					switch(mPuzzleData[i].mHeight) {
					case 3:
						if(!isWithWall) {
							// 6x3(壁なし)を解く
							solve6x3(i, 0, 0);
						} else {
							// 6x3(壁あり)を解く
							if(!solve6x3withWall(i, 0, 0)) {
								mResult[i] = "";
							}
						}
						break;
					case 4:
						if(!isWithWall) {
							// 6x4(壁なし)を解く
							solve6x4(i, 0, 0);
						} else {
							// 6x4(壁あり)を解く
							if(!solve6x4withWall(i, 0, 0)) {
								mResult[i] = "";
							}
						}
						break;
					case 5:
						if(!isWithWall) {
							// 6x5(壁なし)を解く
							solve6x5(i, 0, 0);
						} else {
							// 6x5(壁あり)を解く
							if(!solve6x5withWall(i, 0, 0)) {
								mResult[i] = "";
							}
						}
						break;
					case 6:
						if(!isWithWall) {
							// 6x6(壁なし)を解く
							solve6x6(i, 0, 0);
						} else {
							// 6x6(壁あり)を解く
							if(!solve6x6withWall(i, 0, 0)) {
								mResult[i] = "";
							}
						}
						break;
					default:
						break;
					}
					break;
				default:
					break;
				}
			}
		}
		
		private void solve2x2(int puzzleIndex, int dx, int dy) {
			PuzzleData pzData = mPuzzleData[puzzleIndex];
			int finalData1 = getFinalData(pzData.mWidth, dx, dy);
			int finalData2 = getFinalData(pzData.mWidth, dx+1, dy);
			int finalData3 = getFinalData(pzData.mWidth, dx, dy+1);
			//int finalData4 = getFinishData(2, dx+1, dy+1);
			int finalData4 = SPACE_DATA;
			int data1 = pzData.mData[dy][dx];
			int data2 = pzData.mData[dy][dx+1];
			int data3 = pzData.mData[dy+1][dx];
			//int data4 = pzData.mData[dy+1][dx+1]
			if(data1 == finalData1) {
				if(data2 == finalData2) {
					if(data3 == finalData4) {
						reverse(puzzleIndex, OPE_R);
					}
				} else if(data2 == finalData4) {
					reverse(puzzleIndex, OPE_D);
				}
			} else if(data1 == finalData2) {
				if(data2 == finalData3) {
					if(data3 == finalData1) {
						reverse(puzzleIndex, OPE_U);
						solve2x2(puzzleIndex, dx, dy);
					} else {
						reverse(puzzleIndex, OPE_R);
						solve2x2(puzzleIndex, dx, dy);
					}
				} else if(data2 == finalData4) {
					reverse(puzzleIndex, OPE_L);
					solve2x2(puzzleIndex, dx, dy);
				}
			} else if(data1 == finalData3) {
				if(data2 == finalData1) {
					if(data3 == finalData2) {
						reverse(puzzleIndex, OPE_L);
						solve2x2(puzzleIndex, dx, dy);
					} else {
						reverse(puzzleIndex, OPE_U);
						solve2x2(puzzleIndex, dx, dy);
					}
				} else if(data2 == finalData4) {
					reverse(puzzleIndex, OPE_D);
					solve2x2(puzzleIndex, dx, dy);
				}
			} else if(data1 == finalData4) {
				if(data2 == finalData1) {
					reverse(puzzleIndex, OPE_R);
					solve2x2(puzzleIndex, dx, dy);
				} else if(data2 == finalData2) {
					reverse(puzzleIndex, OPE_D);
					solve2x2(puzzleIndex, dx, dy);
				} else {
					reverse(puzzleIndex, OPE_D);
					solve2x2(puzzleIndex, dx, dy);
				}
			}
		}
	
		private void solve2x3(int puzzleIndex, int dx, int dy) {
			moveToDyDataPositionForSolve2xN(puzzleIndex, dx, dy);
			solve2x2(puzzleIndex, dx, dy+1);
		}
		
		private void moveSpaceDataToData2PositionForSolve2xN(int puzzleIndex, int dx, int dy) {
			PuzzleData pzData = mPuzzleData[puzzleIndex];
			if(pzData.mData[dy][dx+1] == SPACE_DATA) {
				return;
			}
			if(pzData.mZeroX == dx) {
				// 右に移動
				reverse(puzzleIndex, OPE_R);
			}
			while(pzData.mZeroY != dy) {
				// 上に移動
				reverse(puzzleIndex, OPE_U);
			}
		}
		
		private void solve2x4(int puzzleIndex, int dx, int dy) {
			moveToDyDataPositionForSolve2xN(puzzleIndex, dx, dy);
			solve2x3(puzzleIndex, dx, dy+1);
		}
		
		private void solve2x5(int puzzleIndex, int dx, int dy) {
			moveToDyDataPositionForSolve2xN(puzzleIndex, dx, dy);
			solve2x4(puzzleIndex, dx, dy+1);
		}
		
		private void solve2x6(int puzzleIndex, int dx, int dy) {
			moveToDyDataPositionForSolve2xN(puzzleIndex, dx, dy);
			solve2x5(puzzleIndex, dx, dy+1);
		}
		
		private void moveToDyDataPositionForSolve2xN(int puzzleIndex, int dx, int dy) {
			if(isSolveDyPositionSolve(puzzleIndex, dx, dy)) {
				// 揃っている
				return;
			}
			PuzzleData pzData = mPuzzleData[puzzleIndex];
			int finalData1 = getFinalData(pzData.mWidth, dx, dy);
			int finalData2 = getFinalData(pzData.mWidth, dx+1, dy);
			if(pzData.mData[dy][dx] == SPACE_DATA && pzData.mData[dy][dx+1]  == finalData2 && pzData.mData[dy+1][dx]  == finalData1) {
				// 1回下へ移動するだけで揃うので移動
				reverse(puzzleIndex, OPE_D);
				return;
			} else if(pzData.mData[dy][dx+1] == SPACE_DATA && pzData.mData[dy][dx]  == finalData1 && pzData.mData[dy+1][dx+1]  == finalData2) {
				// 1回下へ移動するだけで揃うので移動
				reverse(puzzleIndex, OPE_D);
				return;
			}
			// まず、dx, dyの位置がfinalData2になるようにする
			moveToData1PositionForSolve2xN(puzzleIndex, dx, dy);
			// 次にdx, dy+1の位置がfinalData1になるようにする
			moveToData3PositionForSolve2xN(puzzleIndex, dx, dy);
			// 空白をdx+1, dyに移動
			moveSpaceDataToData2PositionForSolve2xN(puzzleIndex, dx, dy);
			// finalData1をdx,dy、finalData2をdx+1,dyへ移動
			reverse(puzzleIndex, OPE_L);	// finalData2をdx+1,dyへ移動
			reverse(puzzleIndex, OPE_D);	// finalData1をdx,dyへ移動
		}
		
		private void moveToData1PositionForSolve2xN(int puzzleIndex, int dx, int dy) {
			PuzzleData pzData = mPuzzleData[puzzleIndex];
			int targetData = getFinalData(pzData.mWidth, dx+1, dy);
			if(pzData.mData[dy][dx] == targetData) {
				return;
			}
			Position finalData1Pos = getPosition(puzzleIndex, targetData);
			if(finalData1Pos.mX == dx) {
				if(pzData.mZeroX == dx) {
					if(finalData1Pos.mY > pzData.mZeroY) {
						// 下に移動して再帰する
						reverse(puzzleIndex, OPE_D);
						moveToData1PositionForSolve2xN(puzzleIndex, dx, dy);
					} else {
						// 右に移動して再帰する
						reverse(puzzleIndex, OPE_R);
						moveToData1PositionForSolve2xN(puzzleIndex, dx, dy);
					}
				} else {
					if(finalData1Pos.mY > pzData.mZeroY) {
						// 左に移動して再帰する
						reverse(puzzleIndex, OPE_L);
						moveToData1PositionForSolve2xN(puzzleIndex, dx, dy);
					} else {
						// 上に移動して再帰する
						reverse(puzzleIndex, OPE_U);
						moveToData1PositionForSolve2xN(puzzleIndex, dx, dy);
					}
				}
			} else {
				if(pzData.mZeroX == dx) {
					if(finalData1Pos.mY >= pzData.mZeroY) {
						// 右に移動して再帰する
						reverse(puzzleIndex, OPE_R);
						moveToData1PositionForSolve2xN(puzzleIndex, dx, dy);
					} else {
						// 上に移動して再帰する
						reverse(puzzleIndex, OPE_U);
						moveToData1PositionForSolve2xN(puzzleIndex, dx, dy);
					}
				} else {
					if(finalData1Pos.mY > pzData.mZeroY) {
						// 下に移動して再帰する
						reverse(puzzleIndex, OPE_D);
						moveToData1PositionForSolve2xN(puzzleIndex, dx, dy);
					} else {
						// 左に移動して再帰する
						reverse(puzzleIndex, OPE_L);
						moveToData1PositionForSolve2xN(puzzleIndex, dx, dy);
					}
				}
			}
		}
	
		private void moveToData3PositionForSolve2xN(int puzzleIndex, int dx, int dy) {
			PuzzleData pzData = mPuzzleData[puzzleIndex];
			int targetData = getFinalData(pzData.mWidth, dx, dy);
			if(pzData.mData[dy+1][dx] == targetData) {
				return;
			}
			if(pzData.mData[dy][dx+1] == targetData) {
				// 特別な処理が必要
				moveSpecialTargetDataToData2PositionForSolve2xN(puzzleIndex, dx, dy);
			} else if(pzData.mZeroX == dx + 1 && pzData.mZeroY == dy && pzData.mData[dy+1][dx+1] == targetData) {
				// 下に移動する
				reverse(puzzleIndex, OPE_D);
				// 特別な処理が必要
				moveSpecialTargetDataToData2PositionForSolve2xN(puzzleIndex, dx, dy);
			} else {
				moveTargetDataToData2PositionForSolve2xN(puzzleIndex, dx, dy);
			}
		}
		
		private void moveSpecialTargetDataToData2PositionForSolve2xN(int puzzleIndex, int dx, int dy) {
			PuzzleData pzData = mPuzzleData[puzzleIndex];
			if(pzData.mZeroX == dx) {
				// 右に移動する
				reverse(puzzleIndex, OPE_R);
			}
			while(pzData.mZeroY != dy) {
				// 上へ移動
				reverse(puzzleIndex, OPE_U);
			}
			// 左へ移動
			reverse(puzzleIndex, OPE_L);
			// 2回下へ移動
			reverse(puzzleIndex, OPE_D);
			reverse(puzzleIndex, OPE_D);
			// 右へ移動
			reverse(puzzleIndex, OPE_R);
			// 上へ移動
			reverse(puzzleIndex, OPE_U);
			// 左へ移動
			reverse(puzzleIndex, OPE_L);
			// 上へ移動
			reverse(puzzleIndex, OPE_U);
			// 右へ移動
			reverse(puzzleIndex, OPE_R);
			// 2回下へ移動
			reverse(puzzleIndex, OPE_D);
			reverse(puzzleIndex, OPE_D);
			// 左へ移動
			reverse(puzzleIndex, OPE_L);
			// 上へ移動
			reverse(puzzleIndex, OPE_U);
			// 右へ移動
			reverse(puzzleIndex, OPE_R);
		}
		
		private void moveTargetDataToData2PositionForSolve2xN(int puzzleIndex, int dx, int dy) {
			PuzzleData pzData = mPuzzleData[puzzleIndex];
			int targetData = getFinalData(pzData.mWidth, dx, dy);
			if(pzData.mData[dy+1][dx] == targetData) {
				return;
			}
			if(pzData.mZeroX == dx + 1 && pzData.mZeroY == dy) {
				// 下に移動して再帰する
				reverse(puzzleIndex, OPE_D);
				moveTargetDataToData2PositionForSolve2xN(puzzleIndex, dx, dy);
			}
			Position finalData1Pos = getPosition(puzzleIndex, targetData);
			if(finalData1Pos.mX == dx) {
				if(pzData.mZeroX == dx) {
					if(finalData1Pos.mY > pzData.mZeroY) {
						// 下に移動して再帰する
						reverse(puzzleIndex, OPE_D);
						moveTargetDataToData2PositionForSolve2xN(puzzleIndex, dx, dy);
					} else {
						// 右に移動して再帰する
						reverse(puzzleIndex, OPE_R);
						moveTargetDataToData2PositionForSolve2xN(puzzleIndex, dx, dy);
					}
				} else {
					if(finalData1Pos.mY > pzData.mZeroY) {
						// 左に移動して再帰する
						reverse(puzzleIndex, OPE_L);
						moveTargetDataToData2PositionForSolve2xN(puzzleIndex, dx, dy);
					} else {
						// 上に移動して再帰する
						reverse(puzzleIndex, OPE_U);
						moveTargetDataToData2PositionForSolve2xN(puzzleIndex, dx, dy);
					}
				}
			} else {
				if(pzData.mZeroX == dx) {
					if(finalData1Pos.mY >= pzData.mZeroY) {
						// 右に移動して再帰する
						reverse(puzzleIndex, OPE_R);
						moveTargetDataToData2PositionForSolve2xN(puzzleIndex, dx, dy);
					} else {
						// 上に移動して再帰する
						reverse(puzzleIndex, OPE_U);
						moveTargetDataToData2PositionForSolve2xN(puzzleIndex, dx, dy);
					}
				} else {
					if(finalData1Pos.mY > pzData.mZeroY) {
						// 下に移動して再帰する
						reverse(puzzleIndex, OPE_D);
						moveTargetDataToData2PositionForSolve2xN(puzzleIndex, dx, dy);
					} else {
						// 左に移動して再帰する
						reverse(puzzleIndex, OPE_L);
						moveTargetDataToData2PositionForSolve2xN(puzzleIndex, dx, dy);
					}
				}
			}
		}
	
		private void solve3x2(int puzzleIndex, int dx, int dy) {
			moveToDxDataPositionForSolveNx2(puzzleIndex, dx, dy);
			solve2x2(puzzleIndex, dx+1, dy);
		}
		
		private void solve4x2(int puzzleIndex, int dx, int dy) {
			moveToDxDataPositionForSolveNx2(puzzleIndex, dx, dy);
			solve3x2(puzzleIndex, dx+1, dy);
		}
		
		private void solve5x2(int puzzleIndex, int dx, int dy) {
			moveToDxDataPositionForSolveNx2(puzzleIndex, dx, dy);
			solve4x2(puzzleIndex, dx+1, dy);
		}
		
		private void solve6x2(int puzzleIndex, int dx, int dy) {
			moveToDxDataPositionForSolveNx2(puzzleIndex, dx, dy);
			solve5x2(puzzleIndex, dx+1, dy);
		}
		
		private void moveToDxDataPositionForSolveNx2(int puzzleIndex, int dx, int dy) {
			if(isSolveDxPositionSolve(puzzleIndex, dx, dy)) {
				// すでに揃っている
				return;
			}
			PuzzleData pzData = mPuzzleData[puzzleIndex];
			int finalData1 = getFinalData(pzData.mWidth, dx, dy);
			int finalData2 = getFinalData(pzData.mWidth, dx, dy+1);
			if(pzData.mData[dy][dx] == SPACE_DATA && pzData.mData[dy][dx+1]  == finalData1 && pzData.mData[dy+1][dx]  == finalData2) {
				// 1回右へ移動するだけで揃うので移動する
				reverse(puzzleIndex, OPE_R);
				return;
			} else if(pzData.mData[dy+1][dx] == SPACE_DATA && pzData.mData[dy][dx]  == finalData1 && pzData.mData[dy+1][dx+1]  == finalData2) {
				// 1回右へ移動するだけで揃うので移動する
				reverse(puzzleIndex, OPE_R);
				return;
			}
			// finalData2をdx,dyに移動
			moveToData1PositionForSolveNx2(puzzleIndex, dx, dy);
			// finalData1をdx+1,dyに移動
			moveToData2PositionForSolveNx2(puzzleIndex, dx, dy);
			// 揃える
			if(pzData.mZeroY == dy) {
				// 下へ移動
				reverse(puzzleIndex, OPE_D);
			}
			while(pzData.mZeroX != dx) {
				// 左へ移動
				reverse(puzzleIndex, OPE_L);
			}
			// 上へ移動
			reverse(puzzleIndex, OPE_U);
			// 右へ移動
			reverse(puzzleIndex, OPE_R);
		}
		
		private void moveToData1PositionForSolveNx2(int puzzleIndex, int dx, int dy) {
			PuzzleData pzData = mPuzzleData[puzzleIndex];
			int targetData = getFinalData(pzData.mWidth, dx, dy+1);
			if(pzData.mData[dy][dx] == targetData) {
				return;
			}
			Position finalData1Pos = getPosition(puzzleIndex, targetData);
			if(finalData1Pos.mY == dy) {
				if(pzData.mZeroY == dy) {
					if(finalData1Pos.mX > pzData.mZeroX) {
						// 右に移動して再帰する
						reverse(puzzleIndex, OPE_R);
						moveToData1PositionForSolveNx2(puzzleIndex, dx, dy);
					} else {
						// 下に移動して再帰する
						reverse(puzzleIndex, OPE_D);
						moveToData1PositionForSolveNx2(puzzleIndex, dx, dy);
					}
				} else {
					if(finalData1Pos.mX > pzData.mZeroX) {
						// 上に移動して再帰する
						reverse(puzzleIndex, OPE_U);
						moveToData1PositionForSolveNx2(puzzleIndex, dx, dy);
					} else {
						// 左に移動して再帰する
						reverse(puzzleIndex, OPE_L);
						moveToData1PositionForSolveNx2(puzzleIndex, dx, dy);
					}
				}
			} else {
				if(pzData.mZeroY == dy) {
					if(finalData1Pos.mX >= pzData.mZeroX) {
						// 下に移動して再帰する
						reverse(puzzleIndex, OPE_D);
						moveToData1PositionForSolveNx2(puzzleIndex, dx, dy);
					} else {
						// 左に移動して再帰する
						reverse(puzzleIndex, OPE_L);
						moveToData1PositionForSolveNx2(puzzleIndex, dx, dy);
					}
				} else {
					if(finalData1Pos.mX > pzData.mZeroX) {
						// 右に移動して再帰する
						reverse(puzzleIndex, OPE_R);
						moveToData1PositionForSolveNx2(puzzleIndex, dx, dy);
					} else {
						// 上に移動して再帰する
						reverse(puzzleIndex, OPE_U);
						moveToData1PositionForSolveNx2(puzzleIndex, dx, dy);
					}
				}
			}
		}
		
		private void moveToData2PositionForSolveNx2(int puzzleIndex, int dx, int dy) {
			PuzzleData pzData = mPuzzleData[puzzleIndex];
			int targetData = getFinalData(pzData.mWidth, dx, dy);
			if(pzData.mData[dy][dx+1] == targetData) {
				return;
			}
			if(pzData.mData[dy+1][dx] == targetData) {
				// 特別な処理が必要
				moveSpecialTargetDataToData2PositionForSolveNx2(puzzleIndex, dx, dy);
			} else if(pzData.mZeroX == dx && pzData.mZeroY == dy + 1 && pzData.mData[dy+1][dx+1] == targetData) {
				// 右に移動する
				reverse(puzzleIndex, OPE_R);
				// 特別な処理が必要
				moveSpecialTargetDataToData2PositionForSolveNx2(puzzleIndex, dx, dy);
			} else {
				moveTargetDataToData2PositionForSolveNx2(puzzleIndex, dx, dy);
			}
		}
		
		private void moveSpecialTargetDataToData2PositionForSolveNx2(int puzzleIndex, int dx, int dy) {
			PuzzleData pzData = mPuzzleData[puzzleIndex];
			if(pzData.mZeroY == dy) {
				// 下に移動する
				reverse(puzzleIndex, OPE_D);
			}
			while(pzData.mZeroX != dx) {
				// 左へ移動
				reverse(puzzleIndex, OPE_L);
			}
			// 上へ移動
			reverse(puzzleIndex, OPE_U);
			// 2回右へ移動
			reverse(puzzleIndex, OPE_R);
			reverse(puzzleIndex, OPE_R);
			// 下へ移動
			reverse(puzzleIndex, OPE_D);
			// 左へ移動
			reverse(puzzleIndex, OPE_L);
			// 上へ移動
			reverse(puzzleIndex, OPE_U);
			// 左へ移動
			reverse(puzzleIndex, OPE_L);
			// 下へ移動
			reverse(puzzleIndex, OPE_D);
			// 2回右へ移動
			reverse(puzzleIndex, OPE_R);
			reverse(puzzleIndex, OPE_R);
			// 上へ移動
			reverse(puzzleIndex, OPE_U);
			// 左へ移動
			reverse(puzzleIndex, OPE_L);
			// 下へ移動
			reverse(puzzleIndex, OPE_D);
		}
		
		private void moveTargetDataToData2PositionForSolveNx2(int puzzleIndex, int dx, int dy) {
			PuzzleData pzData = mPuzzleData[puzzleIndex];
			int targetData = getFinalData(pzData.mWidth, dx, dy);
			if(pzData.mData[dy][dx+1] == targetData) {
				return;
			}
			if(pzData.mZeroX == dx && pzData.mZeroY == dy + 1) {
				// 右に移動して再帰
				reverse(puzzleIndex, OPE_R);
				moveTargetDataToData2PositionForSolveNx2(puzzleIndex, dx, dy);
				return;
			}
			Position finalData1Pos = getPosition(puzzleIndex, targetData);
			if(finalData1Pos.mY == dy) {
				if(pzData.mZeroY == dy) {
					if(finalData1Pos.mX > pzData.mZeroX) {
						// 右に移動して再帰する
						reverse(puzzleIndex, OPE_R);
						moveTargetDataToData2PositionForSolveNx2(puzzleIndex, dx, dy);
					} else {
						// 下に移動して再帰する
						reverse(puzzleIndex, OPE_D);
						moveTargetDataToData2PositionForSolveNx2(puzzleIndex, dx, dy);
					}
				} else {
					if(finalData1Pos.mX > pzData.mZeroX) {
						// 上に移動して再帰する
						reverse(puzzleIndex, OPE_U);
						moveTargetDataToData2PositionForSolveNx2(puzzleIndex, dx, dy);
					} else {
						// 左に移動して再帰する
						reverse(puzzleIndex, OPE_L);
						moveTargetDataToData2PositionForSolveNx2(puzzleIndex, dx, dy);
					}
				}
			} else {
				if(pzData.mZeroY == dy) {
					if(finalData1Pos.mX >= pzData.mZeroX) {
						// 下に移動して再帰する
						reverse(puzzleIndex, OPE_D);
						moveTargetDataToData2PositionForSolveNx2(puzzleIndex, dx, dy);
					} else {
						// 左に移動して再帰する
						reverse(puzzleIndex, OPE_L);
						moveTargetDataToData2PositionForSolveNx2(puzzleIndex, dx, dy);
					}
				} else {
					if(finalData1Pos.mX > pzData.mZeroX) {
						// 右に移動して再帰する
						reverse(puzzleIndex, OPE_R);
						moveTargetDataToData2PositionForSolveNx2(puzzleIndex, dx, dy);
					} else {
						// 上に移動して再帰する
						reverse(puzzleIndex, OPE_U);
						moveTargetDataToData2PositionForSolveNx2(puzzleIndex, dx, dy);
					}
				}
			}
		}
	
		private void solve3x3(int puzzleIndex, int dx, int dy) {
			if(isSolveDxPositionSolve(puzzleIndex, dx, dy)) {
				// 揃っているので2x3へ
				solve2x3(puzzleIndex, dx+1, dy);
				return;
			} else if(isSolveDyPositionSolve(puzzleIndex, dx, dy)) {
				// 揃っているので3x2へ
				solve3x2(puzzleIndex, dx, dy+1);
				return;
			}
			// まずfinalData1を揃える
			moveFinalData1ToData1PositionForSolveNxM(puzzleIndex, dx, dy);
			// 次にfinalData4を揃える
			moveFinalData4ToData4PositionForSolveNx3(puzzleIndex, dx, dy);
			// 最後にfinalData7を揃える
			moveFinalData7ToData7PositionForSolve3x3(puzzleIndex, dx, dy);
			// 揃ったので2x3へ
			solve2x3(puzzleIndex, dx+1, dy);
		}
	
		private void moveFinalData4ToData4PositionForSolveNx3(int puzzleIndex, int dx, int dy) {
			PuzzleData pzData = mPuzzleData[puzzleIndex];
			int finalData4 = getFinalData(pzData.mWidth, dx, dy+1);
			if(pzData.mData[dy+1][dx] == finalData4) {
				return;
			}
			Position finalData4Pos = getPosition(puzzleIndex, finalData4);
			if(finalData4Pos.mY == dy) {
				if(pzData.mZeroY == dy) {
					reverse(puzzleIndex, OPE_D);
					moveFinalData4ToData4PositionForSolveNx3(puzzleIndex, dx, dy);
				} else {
					if(finalData4Pos.mX > pzData.mZeroX) {
						// 右に移動して再帰する
						reverse(puzzleIndex, OPE_R);
						moveFinalData4ToData4PositionForSolveNx3(puzzleIndex, dx, dy);
					} else if(finalData4Pos.mX < pzData.mZeroX){
						// 左に移動して再帰する
						reverse(puzzleIndex, OPE_L);
						moveFinalData4ToData4PositionForSolveNx3(puzzleIndex, dx, dy);
					} else {
						// 上に移動して再帰する
						reverse(puzzleIndex, OPE_U);
						moveFinalData4ToData4PositionForSolveNx3(puzzleIndex, dx, dy);
					}
				}
			} else if(finalData4Pos.mY == dy + 1) {
				if(pzData.mZeroY == dy) {
					if(finalData4Pos.mX != pzData.mZeroX) {
						// 下に移動して再帰する
						reverse(puzzleIndex, OPE_D);
						moveFinalData4ToData4PositionForSolveNx3(puzzleIndex, dx, dy);
					} else {
						if(finalData4Pos.mX == dx + 1) {
							// 右に移動して再帰する
							reverse(puzzleIndex, OPE_R);
							moveFinalData4ToData4PositionForSolveNx3(puzzleIndex, dx, dy);
						} else {
							// 左に移動して再帰する
							reverse(puzzleIndex, OPE_L);
							moveFinalData4ToData4PositionForSolveNx3(puzzleIndex, dx, dy);
						}
					}
				} else if(pzData.mZeroY == dy + 1) {
					if(finalData4Pos.mX > pzData.mZeroX) {
						// 右に移動して再帰する
						reverse(puzzleIndex, OPE_R);
						moveFinalData4ToData4PositionForSolveNx3(puzzleIndex, dx, dy);
					} else {
						// 下に移動して再帰する
						reverse(puzzleIndex, OPE_D);
						moveFinalData4ToData4PositionForSolveNx3(puzzleIndex, dx, dy);
					}
				} else {
					if(finalData4Pos.mX > pzData.mZeroX) {
						// 上に移動して再帰する
						reverse(puzzleIndex, OPE_U);
						moveFinalData4ToData4PositionForSolveNx3(puzzleIndex, dx, dy);
					} else {
						// 左に移動して再帰する
						reverse(puzzleIndex, OPE_L);
						moveFinalData4ToData4PositionForSolveNx3(puzzleIndex, dx, dy);
					}
				}
			} else {
				if(pzData.mZeroY < dy + 2) {
					if(finalData4Pos.mX >= pzData.mZeroX) {
						// 下に移動して再帰する
						reverse(puzzleIndex, OPE_D);
						moveFinalData4ToData4PositionForSolveNx3(puzzleIndex, dx, dy);
					} else {
						if(pzData.mZeroY == dy) {
							// 下に移動して再帰する
							reverse(puzzleIndex, OPE_D);
							moveFinalData4ToData4PositionForSolveNx3(puzzleIndex, dx, dy);
						} else {
							// 左に移動して再帰する
							reverse(puzzleIndex, OPE_L);
							moveFinalData4ToData4PositionForSolveNx3(puzzleIndex, dx, dy);
						}
					}
				} else {
					if(finalData4Pos.mX > pzData.mZeroX) {
						// 右に移動して再帰する
						reverse(puzzleIndex, OPE_R);
						moveFinalData4ToData4PositionForSolveNx3(puzzleIndex, dx, dy);
					} else {
						// 上に移動して再帰する
						reverse(puzzleIndex, OPE_U);
						moveFinalData4ToData4PositionForSolveNx3(puzzleIndex, dx, dy);
					}
				}
			}
		}
		
		private void moveFinalData7ToData7PositionForSolve3x3(int puzzleIndex, int dx, int dy) {
			PuzzleData pzData = mPuzzleData[puzzleIndex];
			int finalData7 = getFinalData(pzData.mWidth, dx, dy+2);
			if(pzData.mData[dy+2][dx] == finalData7) {
				return;
			}
			// まずdx+1,dyにスペースを移動する
			moveSpaceDataToData2PositionForSolve3x3(puzzleIndex, dx, dy);
			// 次にdx+2,dyのデータがfinalData7であるか判定
			if(pzData.mData[dy][dx + 2] == finalData7) {
				// 右に移動してfinalData7をdx+1,dyへ移動
				reverse(puzzleIndex, OPE_R);
				// 下に移動する
				reverse(puzzleIndex, OPE_D);
				// 次にmoveSpaceDataToData2PositionForSolve3x3を行うことで処理しやすい形へ
				moveSpaceDataToData2PositionForSolve3x3(puzzleIndex, dx, dy);
			}
			// 左へ移動
			reverse(puzzleIndex, OPE_L);
			// 下へ移動
			reverse(puzzleIndex, OPE_D);
			// dx,dy+1にfinalData7を移動する
			moveFinalData7ToData4PositionForSolve3x3area3x2(puzzleIndex, dx, dy);
			// dx,dy+2にスペースを移動する
			moveSpaceDataToData7PositionForSolve3x3(puzzleIndex, dx, dy);
			// 最後に上、上、右と移動することで揃う
			reverse(puzzleIndex, OPE_U);
			reverse(puzzleIndex, OPE_U);
			reverse(puzzleIndex, OPE_R);
		}
		
		private void moveSpaceDataToData2PositionForSolve3x3(int puzzleIndex, int dx, int dy) {
			PuzzleData pzData = mPuzzleData[puzzleIndex];
			if(pzData.mZeroX == dx + 1 && pzData.mZeroY == dy) {
				return;
			}
			if(pzData.mZeroX < dx + 1) {
				// 右に移動して再帰する
				reverse(puzzleIndex, OPE_R);
				moveSpaceDataToData2PositionForSolve3x3(puzzleIndex, dx, dy);
			} else if(pzData.mZeroX > dx + 1) {
				// 左に移動して再帰する
				reverse(puzzleIndex, OPE_L);
				moveSpaceDataToData2PositionForSolve3x3(puzzleIndex, dx, dy);
			} else {
				// 上に移動して再帰する
				reverse(puzzleIndex, OPE_U);
				moveSpaceDataToData2PositionForSolve3x3(puzzleIndex, dx, dy);
			}
		}
	
		private void moveFinalData7ToData4PositionForSolve3x3area3x2(int puzzleIndex, int dx, int dy) {
			PuzzleData pzData = mPuzzleData[puzzleIndex];
			int finalData7 = getFinalData(pzData.mWidth, dx, dy+2);
			if(pzData.mData[dy+1][dx] == finalData7) {
				return;
			}
			Position finalData7Pos = getPosition(puzzleIndex, finalData7);
			if(finalData7Pos.mY == dy + 1) {
				if(pzData.mZeroY == dy + 1) {
					if(finalData7Pos.mX > pzData.mZeroX) {
						// 右に移動して再帰する
						reverse(puzzleIndex, OPE_R);
						moveFinalData7ToData4PositionForSolve3x3area3x2(puzzleIndex, dx, dy);
					} else {
						// 下に移動して再帰する
						reverse(puzzleIndex, OPE_D);
						moveFinalData7ToData4PositionForSolve3x3area3x2(puzzleIndex, dx, dy);
					}
				} else {
					if(finalData7Pos.mX > pzData.mZeroX) {
						// 上に移動して再帰する
						reverse(puzzleIndex, OPE_U);
						moveFinalData7ToData4PositionForSolve3x3area3x2(puzzleIndex, dx, dy);
					} else {
						// 左に移動して再帰する
						reverse(puzzleIndex, OPE_L);
						moveFinalData7ToData4PositionForSolve3x3area3x2(puzzleIndex, dx, dy);
					}
				}
			} else {
				if(pzData.mZeroY == dy + 1) {
					if(finalData7Pos.mX >= pzData.mZeroX){
						// 下に移動して再帰する
						reverse(puzzleIndex, OPE_D);
						moveFinalData7ToData4PositionForSolve3x3area3x2(puzzleIndex, dx, dy);
					} else {
						// 左に移動して再帰する
						reverse(puzzleIndex, OPE_L);
						moveFinalData7ToData4PositionForSolve3x3area3x2(puzzleIndex, dx, dy);
					}
				} else {
					if(finalData7Pos.mX > pzData.mZeroX) {
						// 右に移動して再帰する
						reverse(puzzleIndex, OPE_R);
						moveFinalData7ToData4PositionForSolve3x3area3x2(puzzleIndex, dx, dy);
					} else {
						// 上に移動して再帰する
						reverse(puzzleIndex, OPE_U);
						moveFinalData7ToData4PositionForSolve3x3area3x2(puzzleIndex, dx, dy);
					}
				}
			}
		}
		
		private void moveSpaceDataToData7PositionForSolve3x3(int puzzleIndex, int dx, int dy) {
			PuzzleData pzData = mPuzzleData[puzzleIndex];
			if(pzData.mZeroX == dx && pzData.mZeroY == dy + 2) {
				return;
			}
			if(pzData.mZeroY != dy + 2) {
				// 下に移動して再帰する
				reverse(puzzleIndex, OPE_D);
				moveSpaceDataToData7PositionForSolve3x3(puzzleIndex, dx, dy);
			} else {
				// 左に移動して再帰する
				reverse(puzzleIndex, OPE_L);
				moveSpaceDataToData7PositionForSolve3x3(puzzleIndex, dx, dy);
			}
		}
	
		private void solve3x4(int puzzleIndex, int dx, int dy) {
			if(isSolveDxPositionSolve(puzzleIndex, dx, dy)) {
				// 揃っているので2x4へ
				solve2x4(puzzleIndex, dx+1, dy);
				return;
			} else if(isSolveDyPositionSolve(puzzleIndex, dx, dy)) {
				// 揃っているので3x3へ
				solve3x3(puzzleIndex, dx, dy+1);
				return;
			}
			// まずfinalData1を揃える
			moveFinalData1ToData1PositionForSolveNxM(puzzleIndex, dx, dy);
			// 次にfainalData2を揃える
			moveFinalData2ToData2PositionForSolve3xN(puzzleIndex, dx, dy);
			// 次にfainalData3を揃える
			moveFinalData3ToData3PositionForSolve3xN(puzzleIndex, dx, dy);
			// 揃ったので3x3へ
			solve3x3(puzzleIndex, dx, dy+1);
		}
	
		private void moveFinalData1ToData1PositionForSolveNxM(int puzzleIndex, int dx, int dy) {
			PuzzleData pzData = mPuzzleData[puzzleIndex];
			int finalData1 = getFinalData(pzData.mWidth, dx, dy);
			if(pzData.mData[dy][dx] == finalData1) {
				return;
			}
			Position finalData1Pos = getPosition(puzzleIndex, finalData1);
			if(finalData1Pos.mY == dy) {
				if(pzData.mZeroY == dy) {
					if(finalData1Pos.mX > pzData.mZeroX) {
						// 右に移動して再帰する
						reverse(puzzleIndex, OPE_R);
						moveFinalData1ToData1PositionForSolveNxM(puzzleIndex, dx, dy);
					} else {
						// 下に移動して再帰する
						reverse(puzzleIndex, OPE_D);
						moveFinalData1ToData1PositionForSolveNxM(puzzleIndex, dx, dy);
					}
				} else {
					if(finalData1Pos.mX > pzData.mZeroX) {
						// 上に移動して再帰する
						reverse(puzzleIndex, OPE_U);
						moveFinalData1ToData1PositionForSolveNxM(puzzleIndex, dx, dy);
					} else {
						// 左に移動して再帰する
						reverse(puzzleIndex, OPE_L);
						moveFinalData1ToData1PositionForSolveNxM(puzzleIndex, dx, dy);
					}
				}
			} else if(finalData1Pos.mY > dy && finalData1Pos.mY < pzData.mHeight - 1) {
				if(pzData.mZeroY < finalData1Pos.mY) {
					if(finalData1Pos.mX >= pzData.mZeroX) {
						// 下に移動して再帰する
						reverse(puzzleIndex, OPE_D);
						moveFinalData1ToData1PositionForSolveNxM(puzzleIndex, dx, dy);
					} else {
						// 左に移動して再帰する
						reverse(puzzleIndex, OPE_L);
						moveFinalData1ToData1PositionForSolveNxM(puzzleIndex, dx, dy);
					}
				} else if(finalData1Pos.mY == pzData.mZeroY) {
					if(finalData1Pos.mX > pzData.mZeroX) {
						// 右に移動して再帰する
						reverse(puzzleIndex, OPE_R);
						moveFinalData1ToData1PositionForSolveNxM(puzzleIndex, dx, dy);
					} else {
						// 上に移動して再帰する
						reverse(puzzleIndex, OPE_U);
						moveFinalData1ToData1PositionForSolveNxM(puzzleIndex, dx, dy);
					}
				} else {
					if(finalData1Pos.mX == dx) {
						if(pzData.mZeroX == dx) {
							// 右に移動して再帰する
							reverse(puzzleIndex, OPE_R);
							moveFinalData1ToData1PositionForSolveNxM(puzzleIndex, dx, dy);
						} else {
							// 上に移動して再帰する
							reverse(puzzleIndex, OPE_U);
							moveFinalData1ToData1PositionForSolveNxM(puzzleIndex, dx, dy);
						}
					} else {
						if(finalData1Pos.mX > pzData.mZeroX) {
							// 上に移動して再帰する
							reverse(puzzleIndex, OPE_U);
							moveFinalData1ToData1PositionForSolveNxM(puzzleIndex, dx, dy);
						} else {
							// 左に移動して再帰する
							reverse(puzzleIndex, OPE_L);
							moveFinalData1ToData1PositionForSolveNxM(puzzleIndex, dx, dy);
						}
					}
				}
			} else {
				if(pzData.mZeroY < pzData.mHeight - 1) {
					if(finalData1Pos.mX >= pzData.mZeroX) {
						// 下に移動して再帰する
						reverse(puzzleIndex, OPE_D);
						moveFinalData1ToData1PositionForSolveNxM(puzzleIndex, dx, dy);
					} else {
						// 左に移動して再帰する
						reverse(puzzleIndex, OPE_L);
						moveFinalData1ToData1PositionForSolveNxM(puzzleIndex, dx, dy);
					}
				} else {
					if(finalData1Pos.mX > pzData.mZeroX) {
						// 右に移動して再帰する
						reverse(puzzleIndex, OPE_R);
						moveFinalData1ToData1PositionForSolveNxM(puzzleIndex, dx, dy);
					} else {
						// 上に移動して再帰する
						reverse(puzzleIndex, OPE_U);
						moveFinalData1ToData1PositionForSolveNxM(puzzleIndex, dx, dy);
					}
				}
			}
		}
		
		private void moveFinalData2ToData2PositionForSolve3xN(int puzzleIndex, int dx, int dy) {
			PuzzleData pzData = mPuzzleData[puzzleIndex];
			int finalData2 = getFinalData(pzData.mWidth, dx+1, dy);
			if(pzData.mData[dy][dx+1] == finalData2) {
				return;
			}
			Position finalData2Pos = getPosition(puzzleIndex, finalData2);
			if(finalData2Pos.mX == dx) {
				if(pzData.mZeroX == dx) {
					// 右に移動して再帰する
					reverse(puzzleIndex, OPE_R);
					moveFinalData2ToData2PositionForSolve3xN(puzzleIndex, dx, dy);
				} else {
					if(finalData2Pos.mY > pzData.mZeroY) {
						// 下に移動して再帰する
						reverse(puzzleIndex, OPE_D);
						moveFinalData2ToData2PositionForSolve3xN(puzzleIndex, dx, dy);
					} else if(finalData2Pos.mY < pzData.mZeroY){
						// 上に移動して再帰する
						reverse(puzzleIndex, OPE_U);
						moveFinalData2ToData2PositionForSolve3xN(puzzleIndex, dx, dy);
					} else {
						// 左に移動して再帰する
						reverse(puzzleIndex, OPE_L);
						moveFinalData2ToData2PositionForSolve3xN(puzzleIndex, dx, dy);
					}
				}
			} else if(finalData2Pos.mX == dx + 1 ) {
				if(pzData.mZeroX == dx) {
					if(finalData2Pos.mY != pzData.mZeroY) {
						// 右に移動して再帰する
						reverse(puzzleIndex, OPE_R);
						moveFinalData2ToData2PositionForSolve3xN(puzzleIndex, dx, dy);
					} else {
						if(finalData2Pos.mY == dy + 1) {
							// 下に移動して再帰する
							reverse(puzzleIndex, OPE_D);
							moveFinalData2ToData2PositionForSolve3xN(puzzleIndex, dx, dy);
						} else {
							// 上に移動して再帰する
							reverse(puzzleIndex, OPE_U);
							moveFinalData2ToData2PositionForSolve3xN(puzzleIndex, dx, dy);
						}
					}
				} else if(pzData.mZeroX == dx + 1) {
					if(finalData2Pos.mY > pzData.mZeroY) {
						// 下に移動して再帰する
						reverse(puzzleIndex, OPE_D);
						moveFinalData2ToData2PositionForSolve3xN(puzzleIndex, dx, dy);
					} else {
						// 右に移動して再帰する
						reverse(puzzleIndex, OPE_R);
						moveFinalData2ToData2PositionForSolve3xN(puzzleIndex, dx, dy);
					}
				} else {
					if(finalData2Pos.mY > pzData.mZeroY) {
						// 左に移動して再帰する
						reverse(puzzleIndex, OPE_L);
						moveFinalData2ToData2PositionForSolve3xN(puzzleIndex, dx, dy);
					} else {
						// 上に移動して再帰する
						reverse(puzzleIndex, OPE_U);
						moveFinalData2ToData2PositionForSolve3xN(puzzleIndex, dx, dy);
					}
				}
			} else {
				if(pzData.mZeroX < dx + 2) {
					if(finalData2Pos.mY >= pzData.mZeroY) {
						// 右に移動して再帰する
						reverse(puzzleIndex, OPE_R);
						moveFinalData2ToData2PositionForSolve3xN(puzzleIndex, dx, dy);
					} else {
						if(pzData.mZeroX == dx) {
							// 右に移動して再帰する
							reverse(puzzleIndex, OPE_R);
							moveFinalData2ToData2PositionForSolve3xN(puzzleIndex, dx, dy);
						} else {
							// 上に移動して再帰する
							reverse(puzzleIndex, OPE_U);
							moveFinalData2ToData2PositionForSolve3xN(puzzleIndex, dx, dy);
						}
					}
				} else {
					if(finalData2Pos.mY > pzData.mZeroY) {
						// 下に移動して再帰する
						reverse(puzzleIndex, OPE_D);
						moveFinalData2ToData2PositionForSolve3xN(puzzleIndex, dx, dy);
					} else {
						// 左に移動して再帰する
						reverse(puzzleIndex, OPE_L);
						moveFinalData2ToData2PositionForSolve3xN(puzzleIndex, dx, dy);
					}
				}
			}
		}
		
		private void moveFinalData3ToData3PositionForSolve3xN(int puzzleIndex, int dx, int dy) {
			PuzzleData pzData = mPuzzleData[puzzleIndex];
			int finalData3 = getFinalData(pzData.mWidth, dx+2, dy);
			if(pzData.mData[dy][dx+2] == finalData3) {
				return;
			}
			// まずdx列にfinalData3がいないようにする
			moveToNonDxPositionForSolveNxM(puzzleIndex, finalData3, dx, dy);
			// 次にスペースをdx,dy+1に移動(ただしfinalData3の位置は変えない)
			moveSpaceDataToData4PositionForSolve3xN(puzzleIndex, dx, dy);
			// 上へ移動
			reverse(puzzleIndex, OPE_U);
			// 右へ移動
			reverse(puzzleIndex, OPE_R);
			// dx+1,dyにfinalData3を移動する
			moveToData1Position2xN(puzzleIndex, finalData3, dx+1, dy);
			// dx+2,dyにスペースを移動する
			moveSpaceDataToData2Position2xN(puzzleIndex, dx+1, dy);
			// 2回左に移動
			reverse(puzzleIndex, OPE_L);
			reverse(puzzleIndex, OPE_L);
			// 下に移動
			reverse(puzzleIndex, OPE_D);
		}
	
		private void moveToNonDxPositionForSolveNxM(int puzzleIndex, int targetData, int dx, int dy) {
			PuzzleData pzData = mPuzzleData[puzzleIndex];
			Position targetDataPos = getPosition(puzzleIndex, targetData);
			if(targetDataPos.mX != dx) {
				return;
			}
			if(targetDataPos.mX == pzData.mZeroX) {
				// 右に移動して再帰する
				reverse(puzzleIndex, OPE_R);
				moveToNonDxPositionForSolveNxM(puzzleIndex, targetData, dx, dy);
			} else {
				if(targetDataPos.mY > pzData.mZeroY) {
					// 下に移動して再帰する
					reverse(puzzleIndex, OPE_D);
					moveToNonDxPositionForSolveNxM(puzzleIndex, targetData, dx, dy);
				} else if(targetDataPos.mY < pzData.mZeroY) {
					// 上に移動して再帰する
					reverse(puzzleIndex, OPE_U);
					moveToNonDxPositionForSolveNxM(puzzleIndex, targetData, dx, dy);
				} else {
					// 左に移動して再帰する
					reverse(puzzleIndex, OPE_L);
					moveToNonDxPositionForSolveNxM(puzzleIndex, targetData, dx, dy);
				}
			}
		}
	
		private void moveSpaceDataToData4PositionForSolve3xN(int puzzleIndex, int dx, int dy) {
			PuzzleData pzData = mPuzzleData[puzzleIndex];
			int finalData3 = getFinalData(pzData.mWidth, dx+2, dy);
			Position finalData3Pos = getPosition(puzzleIndex, finalData3);
			if(pzData.mZeroX == dx && pzData.mZeroY == dy+1) {
				return;
			}
			if(pzData.mZeroX == dx) {
				// 上に移動して再帰する
				reverse(puzzleIndex, OPE_U);
				moveSpaceDataToData4PositionForSolve3xN(puzzleIndex, dx, dy);
			} else if(finalData3Pos.mY != pzData.mZeroY) {
				if(pzData.mZeroY != dy) {
					// 左に移動して再帰する
					reverse(puzzleIndex, OPE_L);
					moveSpaceDataToData4PositionForSolve3xN(puzzleIndex, dx, dy);
				} else {
					// 下に移動して再帰する
					reverse(puzzleIndex, OPE_D);
					moveSpaceDataToData4PositionForSolve3xN(puzzleIndex, dx, dy);
				}
			} else if(finalData3Pos.mX > pzData.mZeroX) {
				// 左に移動して再帰する
				reverse(puzzleIndex, OPE_L);
				moveSpaceDataToData4PositionForSolve3xN(puzzleIndex, dx, dy);
			} else if(pzData.mZeroY != dy + 1) {
				// 上に移動して再帰する
				reverse(puzzleIndex, OPE_U);
				moveSpaceDataToData4PositionForSolve3xN(puzzleIndex, dx, dy);
			} else {
				// 下に移動して再帰する
				reverse(puzzleIndex, OPE_D);
				moveSpaceDataToData4PositionForSolve3xN(puzzleIndex, dx, dy);
			}
		}
		
		private void moveToData1Position2xN(int puzzleIndex, int targetData, int dx, int dy) {
			PuzzleData pzData = mPuzzleData[puzzleIndex];
			if(pzData.mData[dy][dx] == targetData) {
				return;
			}
			Position targetDataPos = getPosition(puzzleIndex, targetData);
			if(targetDataPos.mX == dx) {
				if(pzData.mZeroX == dx) {
					if(targetDataPos.mY > pzData.mZeroY) {
						// 下に移動して再帰する
						reverse(puzzleIndex, OPE_D);
						moveToData1Position2xN(puzzleIndex, targetData, dx, dy);
					} else {
						// 右に移動して再帰する
						reverse(puzzleIndex, OPE_R);
						moveToData1Position2xN(puzzleIndex, targetData, dx, dy);
					}
				} else {
					if(targetDataPos.mY > pzData.mZeroY) {
						// 左に移動して再帰する
						reverse(puzzleIndex, OPE_L);
						moveToData1Position2xN(puzzleIndex, targetData, dx, dy);
					} else {
						// 上に移動して再帰する
						reverse(puzzleIndex, OPE_U);
						moveToData1Position2xN(puzzleIndex, targetData, dx, dy);
					}
				}
			} else {
				if(pzData.mZeroX == dx) {
					if(targetDataPos.mY >= pzData.mZeroY){
						// 右に移動して再帰する
						reverse(puzzleIndex, OPE_R);
						moveToData1Position2xN(puzzleIndex, targetData, dx, dy);
					} else {
						// 上に移動して再帰する
						reverse(puzzleIndex, OPE_U);
						moveToData1Position2xN(puzzleIndex, targetData, dx, dy);
					}
				} else {
					if(targetDataPos.mY > pzData.mZeroY) {
						// 下に移動して再帰する
						reverse(puzzleIndex, OPE_D);
						moveToData1Position2xN(puzzleIndex, targetData, dx, dy);
					} else {
						// 左に移動して再帰する
						reverse(puzzleIndex, OPE_L);
						moveToData1Position2xN(puzzleIndex, targetData, dx, dy);
					}
				}
			}
		}
	
		private void moveSpaceDataToData2Position2xN(int puzzleIndex, int dx, int dy) {
			PuzzleData pzData = mPuzzleData[puzzleIndex];
			if(pzData.mZeroX == dx + 1 && pzData.mZeroY == dy) {
				return;
			}
			if(pzData.mZeroX != dx + 1) {
				// 右に移動して再帰する
				reverse(puzzleIndex, OPE_R);
				moveSpaceDataToData2Position2xN(puzzleIndex, dx, dy);
			} else {
				// 上に移動して再帰する
				reverse(puzzleIndex, OPE_U);
				moveSpaceDataToData2Position2xN(puzzleIndex, dx, dy);
			}
		}
		
		private void solve3x5(int puzzleIndex, int dx, int dy) {
			if(isSolveDxPositionSolve(puzzleIndex, dx, dy)) {
				// 揃っているので2x5へ
				solve2x5(puzzleIndex, dx+1, dy);
				return;
			} else if(isSolveDyPositionSolve(puzzleIndex, dx, dy)) {
				// 揃っているので3x4へ
				solve3x4(puzzleIndex, dx, dy+1);
				return;
			}
			// まずfinalData1を揃える
			moveFinalData1ToData1PositionForSolveNxM(puzzleIndex, dx, dy);
			// 次にfainalData2を揃える
			moveFinalData2ToData2PositionForSolve3xN(puzzleIndex, dx, dy);
			// 次にfainalData3を揃える
			moveFinalData3ToData3PositionForSolve3xN(puzzleIndex, dx, dy);
			// 揃ったので3x4へ
			solve3x4(puzzleIndex, dx, dy+1);
		}
		
		private void solve3x6(int puzzleIndex, int dx, int dy) {
			if(isSolveDxPositionSolve(puzzleIndex, dx, dy)) {
				// 揃っているので2x6へ
				solve2x6(puzzleIndex, dx+1, dy);
				return;
			} else if(isSolveDyPositionSolve(puzzleIndex, dx, dy)) {
				// 揃っているので3x5へ
				solve3x5(puzzleIndex, dx, dy+1);
				return;
			}
			// まずfinalData1を揃える
			moveFinalData1ToData1PositionForSolveNxM(puzzleIndex, dx, dy);
			// 次にfainalData2を揃える
			moveFinalData2ToData2PositionForSolve3xN(puzzleIndex, dx, dy);
			// 次にfainalData3を揃える
			moveFinalData3ToData3PositionForSolve3xN(puzzleIndex, dx, dy);
			// 揃ったので3x5へ
			solve3x5(puzzleIndex, dx, dy+1);
		}
		
		private void solve4x3(int puzzleIndex, int dx, int dy) {
			if(isSolveDxPositionSolve(puzzleIndex, dx, dy)) {
				// 揃っているので3x3へ
				solve3x3(puzzleIndex, dx+1, dy);
				return;
			} else if(isSolveDyPositionSolve(puzzleIndex, dx, dy)) {
				// 揃っているので4x2へ
				solve4x2(puzzleIndex, dx, dy+1);
				return;
			}
			// まずfinalData1を揃える
			moveFinalData1ToData1PositionForSolveNxM(puzzleIndex, dx, dy);
			// 次にfinalData5を揃える
			moveFinalData4ToData4PositionForSolveNx3(puzzleIndex, dx, dy);
			// 次にfinalData9を揃える
			moveFinalData9ToData9PositionForSolveNx3(puzzleIndex, dx, dy);
			// 揃ったので3x3へ
			solve3x3(puzzleIndex, dx+1, dy);
		}
		
		private void moveFinalData9ToData9PositionForSolveNx3(int puzzleIndex, int dx, int dy) {
			PuzzleData pzData = mPuzzleData[puzzleIndex];
			int finalData9 = getFinalData(pzData.mWidth, dx, dy+2);
			if(pzData.mData[dy+2][dx] == finalData9) {
				return;
			}
			// まずdy列にfinalData9がいないようにする
			moveToNonDyPositionForSolveNxM(puzzleIndex, finalData9, dx, dy);
			// 次にスペースをdx+1,dyに移動(ただしfinalData9の位置は変えない)
			moveSpaceDataToData2PositionForSolveNx3(puzzleIndex, dx, dy);
			// 左へ移動
			reverse(puzzleIndex, OPE_L);
			// 下へ移動
			reverse(puzzleIndex, OPE_D);
			// dx,dy+1にfinalData9を移動する
			moveToData1PositionNx2(puzzleIndex, finalData9, dx, dy+1);
			
			// dx,dy+2にスペースを移動する
			moveSpaceDataToData5PositionNx2(puzzleIndex, dx, dy+1);
			
			// 2回上に移動
			reverse(puzzleIndex, OPE_U);
			reverse(puzzleIndex, OPE_U);
			// 右に移動
			reverse(puzzleIndex, OPE_R);
		}
	
		private void moveToNonDyPositionForSolveNxM(int puzzleIndex, int targetData, int dx, int dy) {
			PuzzleData pzData = mPuzzleData[puzzleIndex];
			Position targetDataPos = getPosition(puzzleIndex, targetData);
			if(targetDataPos.mY != dy) {
				return;
			}
			if(targetDataPos.mY == pzData.mZeroY) {
				// 下に移動して再帰する
				reverse(puzzleIndex, OPE_D);
				moveToNonDyPositionForSolveNxM(puzzleIndex, targetData, dx, dy);
			} else {
				if(targetDataPos.mX > pzData.mZeroX) {
					// 右に移動して再帰する
					reverse(puzzleIndex, OPE_R);
					moveToNonDyPositionForSolveNxM(puzzleIndex, targetData, dx, dy);
				} else if(targetDataPos.mX < pzData.mZeroX) {
					// 左に移動して再帰する
					reverse(puzzleIndex, OPE_L);
					moveToNonDyPositionForSolveNxM(puzzleIndex, targetData, dx, dy);
				} else {
					// 上に移動して再帰する
					reverse(puzzleIndex, OPE_U);
					moveToNonDyPositionForSolveNxM(puzzleIndex, targetData, dx, dy);
				}
			}
		}
	
		private void moveSpaceDataToData2PositionForSolveNx3(int puzzleIndex, int dx, int dy) {
			PuzzleData pzData = mPuzzleData[puzzleIndex];
			int finalData9 = getFinalData(pzData.mWidth, dx, dy+2);
			Position finalData9Pos = getPosition(puzzleIndex, finalData9);
			if(pzData.mZeroX == dx+1 && pzData.mZeroY == dy) {
				return;
			}
			if(pzData.mZeroY == dy) {
				// 左に移動して再帰する
				reverse(puzzleIndex, OPE_L);
				moveSpaceDataToData2PositionForSolveNx3(puzzleIndex, dx, dy);
			} else if(finalData9Pos.mX != pzData.mZeroX) {
				if(pzData.mZeroX != dx) {
					// 上に移動して再帰する
					reverse(puzzleIndex, OPE_U);
					moveSpaceDataToData2PositionForSolveNx3(puzzleIndex, dx, dy);
				} else {
					// 右に移動して再帰する
					reverse(puzzleIndex, OPE_R);
					moveSpaceDataToData2PositionForSolveNx3(puzzleIndex, dx, dy);
				}
			} else if(finalData9Pos.mY > pzData.mZeroY) {
				// 上に移動して再帰する
				reverse(puzzleIndex, OPE_U);
				moveSpaceDataToData2PositionForSolveNx3(puzzleIndex, dx, dy);
			} else if(pzData.mZeroX != dx + 1) {
				// 左に移動して再帰する
				reverse(puzzleIndex, OPE_L);
				moveSpaceDataToData2PositionForSolveNx3(puzzleIndex, dx, dy);
			} else {
				// 右に移動して再帰する
				reverse(puzzleIndex, OPE_R);
				moveSpaceDataToData2PositionForSolveNx3(puzzleIndex, dx, dy);
			}
		}
		
		private void moveToData1PositionNx2(int puzzleIndex, int targetData, int dx, int dy) {
			PuzzleData pzData = mPuzzleData[puzzleIndex];
			if(pzData.mData[dy][dx] == targetData) {
				return;
			}
			Position targetDataPos = getPosition(puzzleIndex, targetData);
			if(targetDataPos.mY == dy) {
				if(pzData.mZeroY == dy) {
					if(targetDataPos.mX > pzData.mZeroX) {
						// 右に移動して再帰する
						reverse(puzzleIndex, OPE_R);
						moveToData1PositionNx2(puzzleIndex, targetData, dx, dy);
					} else {
						// 下に移動して再帰する
						reverse(puzzleIndex, OPE_D);
						moveToData1PositionNx2(puzzleIndex, targetData, dx, dy);
					}
				} else {
					if(targetDataPos.mX > pzData.mZeroX) {
						// 上に移動して再帰する
						reverse(puzzleIndex, OPE_U);
						moveToData1PositionNx2(puzzleIndex, targetData, dx, dy);
					} else {
						// 左に移動して再帰する
						reverse(puzzleIndex, OPE_L);
						moveToData1PositionNx2(puzzleIndex, targetData, dx, dy);
					}
				}
			} else {
				if(pzData.mZeroY == dy) {
					if(targetDataPos.mX >= pzData.mZeroX){
						// 下に移動して再帰する
						reverse(puzzleIndex, OPE_D);
						moveToData1PositionNx2(puzzleIndex, targetData, dx, dy);
					} else {
						// 左に移動して再帰する
						reverse(puzzleIndex, OPE_L);
						moveToData1PositionNx2(puzzleIndex, targetData, dx, dy);
					}
				} else {
					if(targetDataPos.mX > pzData.mZeroX) {
						// 右に移動して再帰する
						reverse(puzzleIndex, OPE_R);
						moveToData1PositionNx2(puzzleIndex, targetData, dx, dy);
					} else {
						// 上に移動して再帰する
						reverse(puzzleIndex, OPE_U);
						moveToData1PositionNx2(puzzleIndex, targetData, dx, dy);
					}
				}
			}
		}
		
		private void moveSpaceDataToData5PositionNx2(int puzzleIndex, int dx, int dy) {
			PuzzleData pzData = mPuzzleData[puzzleIndex];
			if(pzData.mZeroX == dx && pzData.mZeroY == dy + 1) {
				return;
			}
			if(pzData.mZeroY != dy + 1) {
				// 下に移動して再帰する
				reverse(puzzleIndex, OPE_D);
				moveSpaceDataToData5PositionNx2(puzzleIndex, dx, dy);
			} else {
				// 左に移動して再帰する
				reverse(puzzleIndex, OPE_L);
				moveSpaceDataToData5PositionNx2(puzzleIndex, dx, dy);
			}
		}
		
		private void solve4x4(int puzzleIndex, int dx, int dy) {
			if(isSolveDxPositionSolve(puzzleIndex, dx, dy)) {
				// 揃っているので3x4へ
				solve3x4(puzzleIndex, dx+1, dy);
				return;
			} else if(isSolveDyPositionSolve(puzzleIndex, dx, dy)) {
				// 揃っているので4x3へ
				solve4x3(puzzleIndex, dx, dy+1);
				return;
			}
			// まずfinalData1を揃える
			moveFinalData1ToData1PositionForSolveNxM(puzzleIndex, dx, dy);
			// 次にfinalData5を揃えるため
			PuzzleData pzData = mPuzzleData[puzzleIndex];
			int finalData5 = getFinalData(pzData.mWidth, dx, dy+1);
			moveToNonDyPositionForSolveNxM(puzzleIndex, finalData5, dx, dy);
			moveSpaceDataToNonDyPositionForSolveNxM(puzzleIndex, finalData5, dx+1, dy);
			moveFinalData1ToData1PositionForSolveNxM(puzzleIndex, dx, dy+1);
			// 次にfinalData9を揃える
			int finalData9 = getFinalData(pzData.mWidth, dx, dy+2);
			moveToNonDyPositionForSolveNxM(puzzleIndex, finalData9, dx, dy);
			moveSpaceDataToNonDyPositionForSolveNxM(puzzleIndex, finalData9, dx+1, dy);
			moveFinalData4ToData4PositionForSolveNx3(puzzleIndex, dx, dy+1);
			// 次にfinalData13を揃える
			int finalData13 = getFinalData(pzData.mWidth, dx, dy+3);
			moveToNonDyPositionForSolveNxM(puzzleIndex, finalData13, dx, dy);
			moveSpaceDataToNonDyPositionForSolveNxM(puzzleIndex, finalData13, dx+1, dy);
			moveFinalData9ToData9PositionForSolveNx3(puzzleIndex, dx, dy+1);
			// 揃ったので3x4へ
			solve3x4(puzzleIndex, dx+1, dy);
		}
		
		private void moveSpaceDataToNonDyPositionForSolveNxM(int puzzleIndex, int targetData, int dx, int dy) {
			PuzzleData pzData = mPuzzleData[puzzleIndex];
			if(pzData.mZeroY != dy) {
				return;
			}
			Position targetDataPos = getPosition(puzzleIndex, targetData);
			if(targetDataPos.mX == pzData.mZeroX) {
				if(targetDataPos.mY > pzData.mZeroY + 1) {
					// 下へ移動する
					reverse(puzzleIndex, OPE_D);
				} else if(pzData.mZeroX > dx){
					// 左に移動して再帰する
					reverse(puzzleIndex, OPE_L);
					moveSpaceDataToNonDyPositionForSolveNxM(puzzleIndex, targetData, dx, dy);
				} else {
					// 右に移動して再帰する
					reverse(puzzleIndex, OPE_R);
					moveSpaceDataToNonDyPositionForSolveNxM(puzzleIndex, targetData, dx, dy);
				}
			} else {
				// 下へ移動する
				reverse(puzzleIndex, OPE_D);
			}
		}
	
		private void solve4x5(int puzzleIndex, int dx, int dy) {
			if(isSolveDxPositionSolve(puzzleIndex, dx, dy)) {
				// 揃っているので3x5へ
				solve3x5(puzzleIndex, dx+1, dy);
				return;
			} else if(isSolveDyPositionSolve(puzzleIndex, dx, dy)) {
				// 揃っているので4x4へ
				solve4x4(puzzleIndex, dx, dy+1);
				return;
			}
			// まずfinalData1を揃える
			moveFinalData1ToData1PositionForSolveNxM(puzzleIndex, dx, dy);
			// 次にfinalData2を揃える
			PuzzleData pzData = mPuzzleData[puzzleIndex];
			int finalData2 = getFinalData(pzData.mWidth, dx+1, dy);
			moveToNonDxPositionForSolveNxM(puzzleIndex, finalData2, dx, dy);
			moveSpaceDataToNonDxPositionForSolveNxM(puzzleIndex, finalData2, dx, dy+1);
			moveFinalData1ToData1PositionForSolveNxM(puzzleIndex, dx+1, dy);
			// 次にfinalData3を揃える
			int finalData3 = getFinalData(pzData.mWidth, dx+2, dy);
			moveToNonDxPositionForSolveNxM(puzzleIndex, finalData3, dx, dy);
			moveSpaceDataToNonDxPositionForSolveNxM(puzzleIndex, finalData3, dx, dy+1);
			moveFinalData2ToData2PositionForSolve3xN(puzzleIndex, dx+1, dy);
			// 次にfinalData4を揃える
			int finalData4 = getFinalData(pzData.mWidth, dx+3, dy);
			moveToNonDxPositionForSolveNxM(puzzleIndex, finalData4, dx, dy);
			moveSpaceDataToNonDxPositionForSolveNxM(puzzleIndex, finalData4, dx, dy+1);
			moveFinalData3ToData3PositionForSolve3xN(puzzleIndex, dx+1, dy);
			// 揃ったので4x4へ
			solve4x4(puzzleIndex, dx, dy+1);
		}
		
		private void moveSpaceDataToNonDxPositionForSolveNxM(int puzzleIndex, int targetData, int dx, int dy) {
			PuzzleData pzData = mPuzzleData[puzzleIndex];
			if(pzData.mZeroX != dx) {
				return;
			}
			Position targetDataPos = getPosition(puzzleIndex, targetData);
			if(targetDataPos.mY == pzData.mZeroY) {
				if(targetDataPos.mX > pzData.mZeroX + 1) {
					// 右へ移動する
					reverse(puzzleIndex, OPE_R);
				} else if(pzData.mZeroY > dy){
					// 上に移動して再帰する
					reverse(puzzleIndex, OPE_U);
					moveSpaceDataToNonDxPositionForSolveNxM(puzzleIndex, targetData, dx, dy);
				} else {
					// 下に移動して再帰する
					reverse(puzzleIndex, OPE_D);
					moveSpaceDataToNonDxPositionForSolveNxM(puzzleIndex, targetData, dx, dy);
				}
			} else {
				// 右へ移動する
				reverse(puzzleIndex, OPE_R);
			}
		}
	
		private void solve4x6(int puzzleIndex, int dx, int dy) {
			if(isSolveDxPositionSolve(puzzleIndex, dx, dy)) {
				// 揃っているので3x6へ
				solve3x6(puzzleIndex, dx+1, dy);
				return;
			} else if(isSolveDyPositionSolve(puzzleIndex, dx, dy)) {
				// 揃っているので4x5へ
				solve4x5(puzzleIndex, dx, dy+1);
				return;
			}
			// まずfinalData1を揃える
			moveFinalData1ToData1PositionForSolveNxM(puzzleIndex, dx, dy);
			// 次にfinalData2を揃える
			PuzzleData pzData = mPuzzleData[puzzleIndex];
			int finalData2 = getFinalData(pzData.mWidth, dx+1, dy);
			moveToNonDxPositionForSolveNxM(puzzleIndex, finalData2, dx, dy);
			moveSpaceDataToNonDxPositionForSolveNxM(puzzleIndex, finalData2, dx, dy+1);
			moveFinalData1ToData1PositionForSolveNxM(puzzleIndex, dx+1, dy);
			// 次にfinalData3を揃える
			int finalData3 = getFinalData(pzData.mWidth, dx+2, dy);
			moveToNonDxPositionForSolveNxM(puzzleIndex, finalData3, dx, dy);
			moveSpaceDataToNonDxPositionForSolveNxM(puzzleIndex, finalData3, dx, dy+1);
			moveFinalData2ToData2PositionForSolve3xN(puzzleIndex, dx+1, dy);
			// 次にfinalData4を揃える
			int finalData4 = getFinalData(pzData.mWidth, dx+3, dy);
			moveToNonDxPositionForSolveNxM(puzzleIndex, finalData4, dx, dy);
			moveSpaceDataToNonDxPositionForSolveNxM(puzzleIndex, finalData4, dx, dy+1);
			moveFinalData3ToData3PositionForSolve3xN(puzzleIndex, dx+1, dy);
			// 揃ったので4x5へ
			solve4x5(puzzleIndex, dx, dy+1);
		}
		
		private void solve5x3(int puzzleIndex, int dx, int dy) {
			if(isSolveDxPositionSolve(puzzleIndex, dx, dy)) {
				// 揃っているので4x3へ
				solve4x3(puzzleIndex, dx+1, dy);
				return;
			} else if(isSolveDyPositionSolve(puzzleIndex, dx, dy)) {
				// 揃っているので5x2へ
				solve5x2(puzzleIndex, dx, dy+1);
				return;
			}
			// まずfinalData1を揃える
			moveFinalData1ToData1PositionForSolveNxM(puzzleIndex, dx, dy);
			// 次にfinalData6を揃える
			moveFinalData4ToData4PositionForSolveNx3(puzzleIndex, dx, dy);
			// 次にfinalData11を揃える
			moveFinalData9ToData9PositionForSolveNx3(puzzleIndex, dx, dy);
			// 揃ったので4x3へ
			solve4x3(puzzleIndex, dx+1, dy);
		}
		
		private void solve5x4(int puzzleIndex, int dx, int dy) {
			if(isSolveDxPositionSolve(puzzleIndex, dx, dy)) {
				// 揃っているので4x4へ
				solve4x4(puzzleIndex, dx+1, dy);
				return;
			} else if(isSolveDyPositionSolve(puzzleIndex, dx, dy)) {
				// 揃っているので5x3へ
				solve5x3(puzzleIndex, dx, dy+1);
				return;
			}
			// まずfinalData1を揃える
			moveFinalData1ToData1PositionForSolveNxM(puzzleIndex, dx, dy);
			// 次にfinalData6を揃えるため
			PuzzleData pzData = mPuzzleData[puzzleIndex];
			int finalData6 = getFinalData(pzData.mWidth, dx, dy+1);
			moveToNonDyPositionForSolveNxM(puzzleIndex, finalData6, dx, dy);
			moveSpaceDataToNonDyPositionForSolveNxM(puzzleIndex, finalData6, dx+1, dy);
			moveFinalData1ToData1PositionForSolveNxM(puzzleIndex, dx, dy+1);
			// 次にfinalData11を揃える
			int finalData11 = getFinalData(pzData.mWidth, dx, dy+2);
			moveToNonDyPositionForSolveNxM(puzzleIndex, finalData11, dx, dy);
			moveSpaceDataToNonDyPositionForSolveNxM(puzzleIndex, finalData11, dx+1, dy);
			moveFinalData4ToData4PositionForSolveNx3(puzzleIndex, dx, dy+1);
			// 次にfinalData13を揃える
			int finalData16 = getFinalData(pzData.mWidth, dx, dy+3);
			moveToNonDyPositionForSolveNxM(puzzleIndex, finalData16, dx, dy);
			moveSpaceDataToNonDyPositionForSolveNxM(puzzleIndex, finalData16, dx+1, dy);
			moveFinalData9ToData9PositionForSolveNx3(puzzleIndex, dx, dy+1);
			// 揃ったので4x4へ
			solve4x4(puzzleIndex, dx+1, dy);
		}
		
		private void solve5x5(int puzzleIndex, int dx, int dy) {
			if(isSolveDxPositionSolve(puzzleIndex, dx, dy)) {
				// 揃っているので4x5へ
				solve4x5(puzzleIndex, dx+1, dy);
				return;
			} else if(isSolveDyPositionSolve(puzzleIndex, dx, dy)) {
				// 揃っているので5x4へ;
				solve5x4(puzzleIndex, dx, dy+1);
				return;
			}
			// まずfinalData1を揃える
			moveFinalData1ToData1PositionForSolveNxM(puzzleIndex, dx, dy);
			// 次にfinalData6を揃えるため
			PuzzleData pzData = mPuzzleData[puzzleIndex];
			int finalData6 = getFinalData(pzData.mWidth, dx, dy+1);
			moveToNonDyPositionForSolveNxM(puzzleIndex, finalData6, dx, dy);
			moveSpaceDataToNonDyPositionForSolveNxM(puzzleIndex, finalData6, dx+1, dy);
			moveFinalData1ToData1PositionForSolveNxM(puzzleIndex, dx, dy+1);
			// 次にfinalData11を揃える
			int finalData11 = getFinalData(pzData.mWidth, dx, dy+2);
			moveToNonDyPositionForSolveNxM(puzzleIndex, finalData11, dx, dy);
			moveSpaceDataToNonDyPositionForSolveNxM(puzzleIndex, finalData11, dx+1, dy);
			moveToNonDyPositionForSolveNxM(puzzleIndex, finalData11, dx, dy+1);
			moveSpaceDataToNonDyPositionForSolveNxM(puzzleIndex, finalData11, dx+1, dy+1);
			moveFinalData1ToData1PositionForSolveNxM(puzzleIndex, dx, dy+2);
			// 次にfinalData16を揃える
			int finalData16 = getFinalData(pzData.mWidth, dx, dy+3);
			moveToNonDyPositionForSolveNxM(puzzleIndex, finalData16, dx, dy);
			moveSpaceDataToNonDyPositionForSolveNxM(puzzleIndex, finalData16, dx+1, dy);
			moveToNonDyPositionForSolveNxM(puzzleIndex, finalData16, dx, dy+1);
			moveSpaceDataToNonDyPositionForSolveNxM(puzzleIndex, finalData16, dx+1, dy+1);
			moveFinalData4ToData4PositionForSolveNx3(puzzleIndex, dx, dy+2);
			// 次にfinalData13を揃える
			int finalData21 = getFinalData(pzData.mWidth, dx, dy+4);
			moveToNonDyPositionForSolveNxM(puzzleIndex, finalData21, dx, dy);
			moveSpaceDataToNonDyPositionForSolveNxM(puzzleIndex, finalData21, dx+1, dy);
			moveToNonDyPositionForSolveNxM(puzzleIndex, finalData21, dx, dy+1);
			moveSpaceDataToNonDyPositionForSolveNxM(puzzleIndex, finalData21, dx+1, dy+1);
			moveFinalData9ToData9PositionForSolveNx3(puzzleIndex, dx, dy+2);
			// 揃ったので4x5へ
			solve4x5(puzzleIndex, dx+1, dy);
		}
		
		private void solve5x6(int puzzleIndex, int dx, int dy) {
			if(isSolveDxPositionSolve(puzzleIndex, dx, dy)) {
				// 揃っているので4x6へ
				solve4x6(puzzleIndex, dx+1, dy);
				return;
			} else if(isSolveDyPositionSolve(puzzleIndex, dx, dy)) {
				// 揃っているので5x5へ;
				solve5x5(puzzleIndex, dx, dy+1);
				return;
			}
			// まずfinalData1を揃える
			moveFinalData1ToData1PositionForSolveNxM(puzzleIndex, dx, dy);
			// 次にfinalData2を揃える
			PuzzleData pzData = mPuzzleData[puzzleIndex];
			int finalData2 = getFinalData(pzData.mWidth, dx+1, dy);
			moveToNonDxPositionForSolveNxM(puzzleIndex, finalData2, dx, dy);
			moveSpaceDataToNonDxPositionForSolveNxM(puzzleIndex, finalData2, dx, dy+1);
			moveFinalData1ToData1PositionForSolveNxM(puzzleIndex, dx+1, dy);
			// 次にfinalData3を揃える
			int finalData3 = getFinalData(pzData.mWidth, dx+2, dy);
			moveToNonDxPositionForSolveNxM(puzzleIndex, finalData3, dx, dy);
			moveSpaceDataToNonDxPositionForSolveNxM(puzzleIndex, finalData3, dx, dy+1);
			moveToNonDxPositionForSolveNxM(puzzleIndex, finalData3, dx+1, dy);
			moveSpaceDataToNonDxPositionForSolveNxM(puzzleIndex, finalData3, dx+1, dy+1);
			moveFinalData1ToData1PositionForSolveNxM(puzzleIndex, dx+2, dy);
			// 次にfinalData4を揃える
			int finalData4 = getFinalData(pzData.mWidth, dx+3, dy);
			moveToNonDxPositionForSolveNxM(puzzleIndex, finalData4, dx, dy);
			moveSpaceDataToNonDxPositionForSolveNxM(puzzleIndex, finalData4, dx, dy+1);
			moveToNonDxPositionForSolveNxM(puzzleIndex, finalData4, dx+1, dy);
			moveSpaceDataToNonDxPositionForSolveNxM(puzzleIndex, finalData4, dx+1, dy+1);
			moveFinalData2ToData2PositionForSolve3xN(puzzleIndex, dx+2, dy);
			// 次にfinalData5を揃える
			int finalData5 = getFinalData(pzData.mWidth, dx+4, dy);
			moveToNonDxPositionForSolveNxM(puzzleIndex, finalData5, dx, dy);
			moveSpaceDataToNonDxPositionForSolveNxM(puzzleIndex, finalData5, dx, dy+1);
			moveToNonDxPositionForSolveNxM(puzzleIndex, finalData5, dx+1, dy);
			moveSpaceDataToNonDxPositionForSolveNxM(puzzleIndex, finalData5, dx+1, dy+1);
			moveFinalData3ToData3PositionForSolve3xN(puzzleIndex, dx+2, dy);
			// 揃ったので5x5へ
			solve5x5(puzzleIndex, dx, dy+1);
		}
		
		private void solve6x3(int puzzleIndex, int dx, int dy) {
			if(isSolveDxPositionSolve(puzzleIndex, dx, dy)) {
				// 揃っているので5x3へ
				solve5x3(puzzleIndex, dx+1, dy);
				return;
			} else if(isSolveDyPositionSolve(puzzleIndex, dx, dy)) {
				// 揃っているので6x2へ
				solve6x2(puzzleIndex, dx, dy+1);
				return;
			}
			// まずfinalData1を揃える
			moveFinalData1ToData1PositionForSolveNxM(puzzleIndex, dx, dy);
			// 次にfinalData7を揃える
			moveFinalData4ToData4PositionForSolveNx3(puzzleIndex, dx, dy);
			// 次にfinalData13を揃える
			moveFinalData9ToData9PositionForSolveNx3(puzzleIndex, dx, dy);
			// 揃ったので5x3へ
			solve5x3(puzzleIndex, dx+1, dy);
		}
		
		private void solve6x4(int puzzleIndex, int dx, int dy) {
			if(isSolveDxPositionSolve(puzzleIndex, dx, dy)) {
				// 揃っているので5x4へ
				solve5x4(puzzleIndex, dx+1, dy);
				return;
			} else if(isSolveDyPositionSolve(puzzleIndex, dx, dy)) {
				// 揃っているので6x3へ
				solve6x3(puzzleIndex, dx, dy+1);
				return;
			}
			// まずfinalData1を揃える
			moveFinalData1ToData1PositionForSolveNxM(puzzleIndex, dx, dy);
			// 次にfinalData7を揃えるため
			PuzzleData pzData = mPuzzleData[puzzleIndex];
			int finalData7 = getFinalData(pzData.mWidth, dx, dy+1);
			moveToNonDyPositionForSolveNxM(puzzleIndex, finalData7, dx, dy);
			moveSpaceDataToNonDyPositionForSolveNxM(puzzleIndex, finalData7, dx+1, dy);
			moveFinalData1ToData1PositionForSolveNxM(puzzleIndex, dx, dy+1);
			// 次にfinalData13を揃える
			int finalData13 = getFinalData(pzData.mWidth, dx, dy+2);
			moveToNonDyPositionForSolveNxM(puzzleIndex, finalData13, dx, dy);
			moveSpaceDataToNonDyPositionForSolveNxM(puzzleIndex, finalData13, dx+1, dy);
			moveFinalData4ToData4PositionForSolveNx3(puzzleIndex, dx, dy+1);
			// 次にfinalData19を揃える
			int finalData19 = getFinalData(pzData.mWidth, dx, dy+3);
			moveToNonDyPositionForSolveNxM(puzzleIndex, finalData19, dx, dy);
			moveSpaceDataToNonDyPositionForSolveNxM(puzzleIndex, finalData19, dx+1, dy);
			moveFinalData9ToData9PositionForSolveNx3(puzzleIndex, dx, dy+1);
			// 揃ったので5x4へ
			solve5x4(puzzleIndex, dx+1, dy);
		}
	
		private void solve6x5(int puzzleIndex, int dx, int dy) {
			if(isSolveDxPositionSolve(puzzleIndex, dx, dy)) {
				// 揃っているので5x5へ
				solve5x5(puzzleIndex, dx+1, dy);
				return;
			} else if(isSolveDyPositionSolve(puzzleIndex, dx, dy)) {
				// 揃っているので6x4へ
				solve6x4(puzzleIndex, dx, dy+1);
				return;
			}
			// まずfinalData1を揃える
			moveFinalData1ToData1PositionForSolveNxM(puzzleIndex, dx, dy);
			// 次にfinalData7を揃えるため
			PuzzleData pzData = mPuzzleData[puzzleIndex];
			int finalData7 = getFinalData(pzData.mWidth, dx, dy+1);
			moveToNonDyPositionForSolveNxM(puzzleIndex, finalData7, dx, dy);
			moveSpaceDataToNonDyPositionForSolveNxM(puzzleIndex, finalData7, dx+1, dy);
			moveFinalData1ToData1PositionForSolveNxM(puzzleIndex, dx, dy+1);
			// 次にfinalData13を揃える
			int finalData13 = getFinalData(pzData.mWidth, dx, dy+2);
			moveToNonDyPositionForSolveNxM(puzzleIndex, finalData13, dx, dy);
			moveSpaceDataToNonDyPositionForSolveNxM(puzzleIndex, finalData13, dx+1, dy);
			moveToNonDyPositionForSolveNxM(puzzleIndex, finalData13, dx, dy+1);
			moveSpaceDataToNonDyPositionForSolveNxM(puzzleIndex, finalData13, dx+1, dy+1);
			moveFinalData1ToData1PositionForSolveNxM(puzzleIndex, dx, dy+2);
			// 次にfinalData19を揃える
			int finalData19 = getFinalData(pzData.mWidth, dx, dy+3);
			moveToNonDyPositionForSolveNxM(puzzleIndex, finalData19, dx, dy);
			moveSpaceDataToNonDyPositionForSolveNxM(puzzleIndex, finalData19, dx+1, dy);
			moveToNonDyPositionForSolveNxM(puzzleIndex, finalData19, dx, dy+1);
			moveSpaceDataToNonDyPositionForSolveNxM(puzzleIndex, finalData19, dx+1, dy+1);
			moveFinalData4ToData4PositionForSolveNx3(puzzleIndex, dx, dy+2);
			// 次にfinalData25を揃える
			int finalData25 = getFinalData(pzData.mWidth, dx, dy+4);
			moveToNonDyPositionForSolveNxM(puzzleIndex, finalData25, dx, dy);
			moveSpaceDataToNonDyPositionForSolveNxM(puzzleIndex, finalData25, dx+1, dy);
			moveToNonDyPositionForSolveNxM(puzzleIndex, finalData25, dx, dy+1);
			moveSpaceDataToNonDyPositionForSolveNxM(puzzleIndex, finalData25, dx+1, dy+1);
			moveFinalData9ToData9PositionForSolveNx3(puzzleIndex, dx, dy+2);
			// 揃ったので5x5へ
			solve5x5(puzzleIndex, dx+1, dy);
		}
		
		private void solve6x6(int puzzleIndex, int dx, int dy) {
			if(isSolveDxPositionSolve(puzzleIndex, dx, dy)) {
				// 揃っているので5x6へ
				solve5x6(puzzleIndex, dx+1, dy);
				return;
			} else if(isSolveDyPositionSolve(puzzleIndex, dx, dy)) {
				// 揃っているので6x5へ
				solve6x5(puzzleIndex, dx, dy+1);
				return;
			}
			// まずfinalData1を揃える
			moveFinalData1ToData1PositionForSolveNxM(puzzleIndex, dx, dy);
			// 次にfinalData7を揃えるため
			PuzzleData pzData = mPuzzleData[puzzleIndex];
			int finalData7 = getFinalData(pzData.mWidth, dx, dy+1);
			moveToNonDyPositionForSolveNxM(puzzleIndex, finalData7, dx, dy);
			moveSpaceDataToNonDyPositionForSolveNxM(puzzleIndex, finalData7, dx+1, dy);
			moveFinalData1ToData1PositionForSolveNxM(puzzleIndex, dx, dy+1);
			// 次にfinalData13を揃える
			int finalData13 = getFinalData(pzData.mWidth, dx, dy+2);
			moveToNonDyPositionForSolveNxM(puzzleIndex, finalData13, dx, dy);
			moveSpaceDataToNonDyPositionForSolveNxM(puzzleIndex, finalData13, dx+1, dy);
			moveToNonDyPositionForSolveNxM(puzzleIndex, finalData13, dx, dy+1);
			moveSpaceDataToNonDyPositionForSolveNxM(puzzleIndex, finalData13, dx+1, dy+1);
			moveFinalData1ToData1PositionForSolveNxM(puzzleIndex, dx, dy+2);
			// 次にfinalData19を揃える
			int finalData19 = getFinalData(pzData.mWidth, dx, dy+3);
			moveToNonDyPositionForSolveNxM(puzzleIndex, finalData19, dx, dy);
			moveSpaceDataToNonDyPositionForSolveNxM(puzzleIndex, finalData19, dx+1, dy);
			moveToNonDyPositionForSolveNxM(puzzleIndex, finalData19, dx, dy+1);
			moveSpaceDataToNonDyPositionForSolveNxM(puzzleIndex, finalData19, dx+1, dy+1);
			moveToNonDyPositionForSolveNxM(puzzleIndex, finalData19, dx, dy+2);
			moveSpaceDataToNonDyPositionForSolveNxM(puzzleIndex, finalData19, dx+1, dy+2);
			moveFinalData1ToData1PositionForSolveNxM(puzzleIndex, dx, dy+3);
			// 次にfinalData25を揃える
			int finalData25 = getFinalData(pzData.mWidth, dx, dy+4);
			moveToNonDyPositionForSolveNxM(puzzleIndex, finalData25, dx, dy);
			moveSpaceDataToNonDyPositionForSolveNxM(puzzleIndex, finalData25, dx+1, dy);
			moveToNonDyPositionForSolveNxM(puzzleIndex, finalData25, dx, dy+1);
			moveSpaceDataToNonDyPositionForSolveNxM(puzzleIndex, finalData25, dx+1, dy+1);
			moveToNonDyPositionForSolveNxM(puzzleIndex, finalData25, dx, dy+2);
			moveSpaceDataToNonDyPositionForSolveNxM(puzzleIndex, finalData25, dx+1, dy+2);
			moveFinalData4ToData4PositionForSolveNx3(puzzleIndex, dx, dy+3);
			// 次にfinalData31を揃える
			int finalData31 = getFinalData(pzData.mWidth, dx, dy+5);
			moveToNonDyPositionForSolveNxM(puzzleIndex, finalData31, dx, dy);
			moveSpaceDataToNonDyPositionForSolveNxM(puzzleIndex, finalData31, dx+1, dy);
			moveToNonDyPositionForSolveNxM(puzzleIndex, finalData31, dx, dy+1);
			moveSpaceDataToNonDyPositionForSolveNxM(puzzleIndex, finalData31, dx+1, dy+1);
			moveToNonDyPositionForSolveNxM(puzzleIndex, finalData31, dx, dy+2);
			moveSpaceDataToNonDyPositionForSolveNxM(puzzleIndex, finalData31, dx+1, dy+2);
			moveFinalData9ToData9PositionForSolveNx3(puzzleIndex, dx, dy+3);
			// 揃ったので5x6へ
			solve5x6(puzzleIndex, dx+1, dy);
		}
		
		private boolean isSolveDxPositionSolve(int puzzleIndex, int dx, int dy) {
			PuzzleData pzData = mPuzzleData[puzzleIndex];
			for(int i = dy; i < pzData.mHeight; i++) {
				int finalData = getFinalData(pzData.mWidth, dx, i);
				int targetData = pzData.mData[i][dx];
				if(targetData != finalData && targetData != WALL_DATA) {
					return false;
				}
			}
			return true;
		}
	
		private boolean isSolveDyPositionSolve(int puzzleIndex, int dx, int dy) {
			PuzzleData pzData = mPuzzleData[puzzleIndex];
			for(int i = dx; i < pzData.mWidth; i++) {
				int finalData = getFinalData(pzData.mWidth, i, dy);
				int targetData = pzData.mData[dy][i];
				if(targetData != finalData && targetData != WALL_DATA) {
					return false;
				}
			}
			return true;
		}
	
		private boolean solve2x2withWall(int puzzleIndex, int dx, int dy) {
			PuzzleData pzData = mPuzzleData[puzzleIndex];
			String tmp = mResult[puzzleIndex];
			String serchReslt = searchAllWay(pzData, puzzleIndex, dx, dy, 0, OPE_N, 20);
			if(serchReslt == null) {
				mResult[puzzleIndex] = tmp;
				return false;
			}
			mResult[puzzleIndex] = tmp + serchReslt;
			return true;
			//return false;
		}
	
		private boolean solve2x3withWall(int puzzleIndex, int dx, int dy) {
			PuzzleData pzData = mPuzzleData[puzzleIndex];
			if(isSolveDyPositionSolve(puzzleIndex, dx, dy)) {
				// 揃っているので2x2へ
				if(!isPussleWithWall(puzzleIndex, dx, dy+1)) {
					solve2x2(puzzleIndex, dx, dy+1);
					return true;
				}
				String strResult = mResult[puzzleIndex];
				if(solve2x2withWall(puzzleIndex, dx, dy+1)) {
					return true;
				}
				// 解けなかったので戻す
				mResult[puzzleIndex] = strResult;
			}
			String tmp = mResult[puzzleIndex];
			String serchReslt = searchAllWay(pzData, puzzleIndex, dx, dy, 0, OPE_N, 20);
			if(serchReslt == null) {
				mResult[puzzleIndex] = tmp;
				return false;
			}
			mResult[puzzleIndex] = tmp + serchReslt;
			return true;
			//return false;
		}
		
		private boolean solve2x4withWall(int puzzleIndex, int dx, int dy) {
			PuzzleData pzData = mPuzzleData[puzzleIndex];
			if(isSolveDyPositionSolve(puzzleIndex, dx, dy)) {
				// 揃っているので2x3へ
				if(!isPussleWithWall(puzzleIndex, dx, dy+1)) {
					solve2x3(puzzleIndex, dx, dy+1);
					return true;
				}
				String strResult = mResult[puzzleIndex];
				if(solve2x3withWall(puzzleIndex, dx, dy+1)) {
					return true;
				}
				// 解けなかったので戻す
				mResult[puzzleIndex] = strResult;
			}
			String tmp = mResult[puzzleIndex];
			String serchReslt = searchAllWay(pzData, puzzleIndex, dx, dy, 0, OPE_N, 20);
			if(serchReslt == null) {
				mResult[puzzleIndex] = tmp;
				return false;
			}
			mResult[puzzleIndex] = tmp + serchReslt;
			return true;
			//return false;
		}
		
		private boolean solve2x5withWall(int puzzleIndex, int dx, int dy) {
			PuzzleData pzData = mPuzzleData[puzzleIndex];
			if(isSolveDyPositionSolve(puzzleIndex, dx, dy)) {
				// 揃っているので2x4へ
				if(!isPussleWithWall(puzzleIndex, dx, dy+1)) {
					solve2x4(puzzleIndex, dx, dy+1);
					return true;
				}
				String strResult = mResult[puzzleIndex];
				if(solve2x4withWall(puzzleIndex, dx, dy+1)) {
					return true;
				}
				// 解けなかったので戻す
				mResult[puzzleIndex] = strResult;
			}
			String tmp = mResult[puzzleIndex];
			String serchReslt = searchAllWay(pzData, puzzleIndex, dx, dy, 0, OPE_N, 20);
			if(serchReslt == null) {
				mResult[puzzleIndex] = tmp;
				return false;
			}
			mResult[puzzleIndex] = tmp + serchReslt;
			return true;
			//return false;
		}
		
		private boolean solve2x6withWall(int puzzleIndex, int dx, int dy) {
			PuzzleData pzData = mPuzzleData[puzzleIndex];
			if(isSolveDyPositionSolve(puzzleIndex, dx, dy)) {
				// 揃っているので2x5へ
				if(!isPussleWithWall(puzzleIndex, dx, dy+1)) {
					solve2x5(puzzleIndex, dx, dy+1);
					return true;
				}
				String strResult = mResult[puzzleIndex];
				if(solve2x5withWall(puzzleIndex, dx, dy+1)) {
					return true;
				}
				// 解けなかったので戻す
				mResult[puzzleIndex] = strResult;
			}
			String tmp = mResult[puzzleIndex];
			String serchReslt = searchAllWay(pzData, puzzleIndex, dx, dy, 0, OPE_N, 20);
			if(serchReslt == null) {
				mResult[puzzleIndex] = tmp;
				return false;
			}
			mResult[puzzleIndex] = tmp + serchReslt;
			return true;
			//return false;
		}
	
		private boolean solve3x2withWall(int puzzleIndex, int dx, int dy) {
			PuzzleData pzData = mPuzzleData[puzzleIndex];
			if(isSolveDxPositionSolve(puzzleIndex, dx, dy)) {
				// 揃っているので2x2へ
				if(!isPussleWithWall(puzzleIndex, dx+1, dy)) {
					solve2x2(puzzleIndex, dx+1, dy);
					return true;
				}
				String strResult = mResult[puzzleIndex];
				if(solve2x2withWall(puzzleIndex, dx+1, dy)) {
					return true;
				}
				// 解けなかったので戻す
				mResult[puzzleIndex] = strResult;
			}
			String tmp = mResult[puzzleIndex];
			String serchReslt = searchAllWay(pzData, puzzleIndex, dx, dy, 0, OPE_N, 20);
			if(serchReslt == null) {
				mResult[puzzleIndex] = tmp;
				return false;
			}
			mResult[puzzleIndex] = tmp + serchReslt;
			return true;
			//return false;
		}
		
		private boolean solve4x2withWall(int puzzleIndex, int dx, int dy) {
			PuzzleData pzData = mPuzzleData[puzzleIndex];
			if(isSolveDxPositionSolve(puzzleIndex, dx, dy)) {
				// 揃っているので3x2へ
				if(!isPussleWithWall(puzzleIndex, dx+1, dy)) {
					solve3x2(puzzleIndex, dx+1, dy);
					return true;
				}
				String strResult = mResult[puzzleIndex];
				if(solve3x2withWall(puzzleIndex, dx+1, dy)) {
					return true;
				}
				// 解けなかったので戻す
				mResult[puzzleIndex] = strResult;
			}
			String tmp = mResult[puzzleIndex];
			String serchReslt = searchAllWay(pzData, puzzleIndex, dx, dy, 0, OPE_N, 20);
			if(serchReslt == null) {
				mResult[puzzleIndex] = tmp;
				return false;
			}
			mResult[puzzleIndex] = tmp + serchReslt;
			return true;
			//return false;
		}
		
		private boolean solve5x2withWall(int puzzleIndex, int dx, int dy) {
			PuzzleData pzData = mPuzzleData[puzzleIndex];
			if(isSolveDxPositionSolve(puzzleIndex, dx, dy)) {
				// 揃っているので4x2へ
				if(!isPussleWithWall(puzzleIndex, dx+1, dy)) {
					solve4x2(puzzleIndex, dx+1, dy);
					return true;
				}
				String strResult = mResult[puzzleIndex];
				if(solve4x2withWall(puzzleIndex, dx+1, dy)) {
					return true;
				}
				// 解けなかったので戻す
				mResult[puzzleIndex] = strResult;
			}
			String tmp = mResult[puzzleIndex];
			String serchReslt = searchAllWay(pzData, puzzleIndex, dx, dy, 0, OPE_N, 20);
			if(serchReslt == null) {
				mResult[puzzleIndex] = tmp;
				return false;
			}
			mResult[puzzleIndex] = tmp + serchReslt;
			return true;
			//return false;
		}
		
		private boolean solve6x2withWall(int puzzleIndex, int dx, int dy) {
			PuzzleData pzData = mPuzzleData[puzzleIndex];
			if(isSolveDxPositionSolve(puzzleIndex, dx, dy)) {
				// 揃っているので5x2へ
				if(!isPussleWithWall(puzzleIndex, dx+1, dy)) {
					solve5x2(puzzleIndex, dx+1, dy);
					return true;
				}
				String strResult = mResult[puzzleIndex];
				if(solve5x2withWall(puzzleIndex, dx+1, dy)) {
					return true;
				}
				// 解けなかったので戻す
				mResult[puzzleIndex] = strResult;
			}
			String tmp = mResult[puzzleIndex];
			String serchReslt = searchAllWay(pzData, puzzleIndex, dx, dy, 0, OPE_N, 20);
			if(serchReslt == null) {
				mResult[puzzleIndex] = tmp;
				return false;
			}
			mResult[puzzleIndex] = tmp + serchReslt;
			return true;
			//return false;
		}
	
		private boolean solve3x3withWall(int puzzleIndex, int dx, int dy) {
			PuzzleData pzData = mPuzzleData[puzzleIndex];
			PuzzleData copy = copyPuzzleData(pzData);
			if(isSolveDxPositionSolve(puzzleIndex, dx, dy)) {
				// 揃っているので2x3へ
				if(!isPussleWithWall(puzzleIndex, dx+1, dy)) {
					solve2x3(puzzleIndex, dx+1, dy);
					return true;
				}
				String strResult = mResult[puzzleIndex];
				if(solve2x3withWall(puzzleIndex, dx+1, dy)) {
					return true;
				}
				// 解けなかったので戻す
				mResult[puzzleIndex] = strResult;
				copyPuzzleData(copy, pzData);
			}
			if(isSolveDyPositionSolve(puzzleIndex, dx, dy)) {
				// 揃っているので3x2へ
				if(!isPussleWithWall(puzzleIndex, dx, dy+1)) {
					solve3x2(puzzleIndex, dx, dy+1);
					return true;
				}
				String strResult = mResult[puzzleIndex];
				if(solve3x2withWall(puzzleIndex, dx, dy+1)) {
					return true;
				}
				// 解けなかったので戻す
				mResult[puzzleIndex] = strResult;
				copyPuzzleData(copy, pzData);
			}
			int wallCount = getWallCount(puzzleIndex, dx, dy);
			if(wallCount > 2) {
				return false;
			} else if(wallCount == 2) {
				if(pzData.mData[dy][dx+2] != WALL_DATA || pzData.mData[dy+2][dx] != WALL_DATA) {
					return false;
				}
				String tmp = mResult[puzzleIndex];
				String serchReslt = searchAllWay(pzData, puzzleIndex, dx, dy, 0, OPE_N, 30);
				if(serchReslt == null) {
					mResult[puzzleIndex] = tmp;
					copyPuzzleData(copy, pzData);
					return false;
				}
				mResult[puzzleIndex] = tmp + serchReslt;
				return true;
			}
			if(wallCount == 1){
				if(pzData.mData[dy][dx] == WALL_DATA) {
					int finalData7 = getFinalData(pzData.mWidth, dx, dy+2);
					moveToNonDyPositionForSolveNxM(puzzleIndex, finalData7, dx, dy);
					moveSpaceDataToNonDyPositionForSolveNxM(puzzleIndex, finalData7, dx+1, dy);
					moveToData1PositionNx2(puzzleIndex, finalData7, dx, dy+1);
					int finalData4 = getFinalData(pzData.mWidth, dx, dy+1);
					moveToNonDyPositionForSolveNxM(puzzleIndex, finalData4, dx, dy);
					moveSpaceDataToNonDyPositionForSolveNxM(puzzleIndex, finalData4, dx+1, dy);
					moveToDxDataPositionForSolveNx2(puzzleIndex, dx, dy+1);
					// 残った2x3には壁はないので2x3を揃える
					solve2x3(puzzleIndex, dx+1, dy);
					return true;
				} else if(pzData.mData[dy][dx+2] == WALL_DATA) {
					int finalData2 = getFinalData(pzData.mWidth, dx+1, dy);
					moveToNonWidthPositionForSolveNxM(puzzleIndex, finalData2, dx, dy);
					moveSpaceDataToNonWidthPositionForSolveNxM(puzzleIndex, finalData2, dx, dy+1);
					moveToData1Position2xN(puzzleIndex, finalData2, dx, dy);
					int finalData1 = getFinalData(pzData.mWidth, dx, dy);
					moveToNonWidthPositionForSolveNxM(puzzleIndex, finalData1, dx, dy);
					moveSpaceDataToNonWidthPositionForSolveNxM(puzzleIndex, finalData1, dx, dy+1);
					moveToDyDataPositionForSolve2xN(puzzleIndex, dx, dy);
					// 残った3x2には壁はないので3x2を揃える
					solve3x2(puzzleIndex, dx, dy+1);
					return true;
				} else if(pzData.mData[dy+2][dx] == WALL_DATA) {
					int finalData4 = getFinalData(pzData.mWidth, dx, dy+1);
					moveToNonHeightPositionForSolveNxM(puzzleIndex, finalData4, dx, dy);
					moveSpaceDataToNonHeightPositionForSolveNxM(puzzleIndex, finalData4, dx+1, dy);
					moveToData1PositionNx2(puzzleIndex, finalData4, dx, dy);
					int finalData1 = getFinalData(pzData.mWidth, dx, dy);
					moveToNonHeightPositionForSolveNxM(puzzleIndex, finalData1, dx, dy);
					moveSpaceDataToNonHeightPositionForSolveNxM(puzzleIndex, finalData1, dx+1, dy);
					moveToDxDataPositionForSolveNx2(puzzleIndex, dx, dy);
					// 残った2x3には壁はないので2x3を揃える
					solve2x3(puzzleIndex, dx+1, dy);
					return true;
				} else if(pzData.mData[dy+1][dx+1] == WALL_DATA) {
					String tmp = mResult[puzzleIndex];
					String serchReslt = searchAllWay(pzData, puzzleIndex, dx, dy, 0, OPE_N, 100);
					if(serchReslt == null) {
						mResult[puzzleIndex] = tmp;
						copyPuzzleData(copy, pzData);
						return false;
					}
					mResult[puzzleIndex] = tmp + serchReslt;
					return true;
				}
			}
			return false;
		}
		
		private void moveToNonWidthPositionForSolveNxM(int puzzleIndex, int targetData, int dx, int dy) {
			PuzzleData pzData = mPuzzleData[puzzleIndex];
			Position targetDataPos = getPosition(puzzleIndex, targetData);
			if(targetDataPos.mX != pzData.mWidth - 1) {
				return;
			}
			if(targetDataPos.mX == pzData.mZeroX) {
				// 左に移動して再帰する
				reverse(puzzleIndex, OPE_L);
				moveToNonWidthPositionForSolveNxM(puzzleIndex, targetData, dx, dy);
			} else {
				if(targetDataPos.mY > pzData.mZeroY) {
					// 下に移動して再帰する
					reverse(puzzleIndex, OPE_D);
					moveToNonWidthPositionForSolveNxM(puzzleIndex, targetData, dx, dy);
				} else if(targetDataPos.mY < pzData.mZeroY) {
					// 上に移動して再帰する
					reverse(puzzleIndex, OPE_U);
					moveToNonWidthPositionForSolveNxM(puzzleIndex, targetData, dx, dy);
				} else {
					// 右に移動して再帰する
					reverse(puzzleIndex, OPE_R);
					moveToNonWidthPositionForSolveNxM(puzzleIndex, targetData, dx, dy);
				}
			}
		}
		
		private void moveSpaceDataToNonWidthPositionForSolveNxM(int puzzleIndex, int targetData, int dx, int dy) {
			PuzzleData pzData = mPuzzleData[puzzleIndex];
			if(pzData.mZeroX != pzData.mWidth - 1) {
				return;
			}
			Position targetDataPos = getPosition(puzzleIndex, targetData);
			if(targetDataPos.mY == pzData.mZeroY) {
				if(targetDataPos.mX < pzData.mZeroX - 1) {
					// 左へ移動する
					reverse(puzzleIndex, OPE_L);
				} else if(pzData.mZeroY > dy){
					// 上に移動して再帰する
					reverse(puzzleIndex, OPE_U);
					moveSpaceDataToNonWidthPositionForSolveNxM(puzzleIndex, targetData, dx, dy);
				} else {
					// 下に移動して再帰する
					reverse(puzzleIndex, OPE_D);
					moveSpaceDataToNonWidthPositionForSolveNxM(puzzleIndex, targetData, dx, dy);
				}
			} else {
				// 左へ移動する
				reverse(puzzleIndex, OPE_L);
			}
		}
		
		private void moveToNonHeightPositionForSolveNxM(int puzzleIndex, int targetData, int dx, int dy) {
			PuzzleData pzData = mPuzzleData[puzzleIndex];
			Position targetDataPos = getPosition(puzzleIndex, targetData);
			if(targetDataPos.mY != pzData.mHeight - 1) {
				return;
			}
			if(targetDataPos.mY == pzData.mZeroY) {
				// 上に移動して再帰する
				reverse(puzzleIndex, OPE_U);
				moveToNonHeightPositionForSolveNxM(puzzleIndex, targetData, dx, dy);
			} else {
				if(targetDataPos.mX > pzData.mZeroX) {
					// 右に移動して再帰する
					reverse(puzzleIndex, OPE_R);
					moveToNonHeightPositionForSolveNxM(puzzleIndex, targetData, dx, dy);
				} else if(targetDataPos.mX < pzData.mZeroX) {
					// 左に移動して再帰する
					reverse(puzzleIndex, OPE_L);
					moveToNonHeightPositionForSolveNxM(puzzleIndex, targetData, dx, dy);
				} else {
					// 下に移動して再帰する
					reverse(puzzleIndex, OPE_D);
					moveToNonHeightPositionForSolveNxM(puzzleIndex, targetData, dx, dy);
				}
			}
		}
		
		private void moveSpaceDataToNonHeightPositionForSolveNxM(int puzzleIndex, int targetData, int dx, int dy) {
			PuzzleData pzData = mPuzzleData[puzzleIndex];
			if(pzData.mZeroY != pzData.mHeight - 1) {
				return;
			}
			Position targetDataPos = getPosition(puzzleIndex, targetData);
			if(targetDataPos.mX == pzData.mZeroX) {
				if(targetDataPos.mY > pzData.mZeroY + 1) {
					// 上へ移動する
					reverse(puzzleIndex, OPE_U);
				} else if(pzData.mZeroX > dx){
					// 左に移動して再帰する
					reverse(puzzleIndex, OPE_L);
					moveSpaceDataToNonHeightPositionForSolveNxM(puzzleIndex, targetData, dx, dy);
				} else {
					// 右に移動して再帰する
					reverse(puzzleIndex, OPE_R);
					moveSpaceDataToNonHeightPositionForSolveNxM(puzzleIndex, targetData, dx, dy);
				}
			} else {
				// 上へ移動する
				reverse(puzzleIndex, OPE_U);
			}
		}
	
		private int getWallCount(int puzzleIndex, int dx, int dy) {
			int count = 0; 
			PuzzleData pzData = mPuzzleData[puzzleIndex];
			for(int i = 0; i < pzData.mHeight ;i++) {
				for(int j = 0; j < pzData.mWidth; j++) {
					if(pzData.mData[i][j] == WALL_DATA) {
						count++;
					}
				}
			}
			return count;
		}
	
		private String searchAllWay(PuzzleData pzData, int puzzleIndex, int dx, int dy, int count, int preOperation, int maxCount) {
			if(count > maxCount) {
				return null;
			}
			boolean allClear = true;
			for(int i = dy; i < pzData.mHeight && allClear == true; i++) {
				for(int j = dx; j < pzData.mWidth && allClear == true; j++) {
					if(i == pzData.mHeight - 1 && j == pzData.mWidth - 1) {
						if(pzData.mData[i][j] == SPACE_DATA) {
							// 全部そろっている
							return "";
						}
					} else {
						if(pzData.mData[i][j] != getFinalData(pzData.mWidth, j, i) && pzData.mData[i][j] != WALL_DATA) {
							allClear = false;
						}
					}
				}
			}
			PuzzleData copy_l = copyPuzzleData(pzData);
			PuzzleData copy_r = copyPuzzleData(pzData);
			PuzzleData copy_u = copyPuzzleData(pzData);
			PuzzleData copy_d = copyPuzzleData(pzData);
			String st_l = null;
			String st_r = null;
			String st_u = null;
			String st_d = null;
			int maxCount2 = maxCount;
			if(copy_l.mZeroX > dx
					&& copy_l.mData[copy_l.mZeroY][copy_l.mZeroX - 1] != WALL_DATA
					&& preOperation != OPE_R) {
				reverse(copy_l, puzzleIndex, OPE_L);
				String result = searchAllWay(copy_l, puzzleIndex, dx, dy, count + 1, OPE_L, maxCount2);
				if(result != null) {
					st_l = "L" + result;
					maxCount2 = count + result.length();
				}
			}
			
			if(copy_u.mZeroY > dy
					&& copy_u.mData[copy_u.mZeroY - 1][copy_u.mZeroX] != WALL_DATA
					&& preOperation != OPE_D) {
				reverse(copy_u, puzzleIndex, OPE_U);
				String result = searchAllWay(copy_u, puzzleIndex, dx, dy, count + 1, OPE_U, maxCount2);
				if(result != null) {
					st_u = "U" + result;
					maxCount2 = count + result.length();
				}
			}
			
			if(copy_r.mZeroX < copy_r.mWidth - 1
					&& copy_r.mData[copy_r.mZeroY][copy_r.mZeroX + 1] != WALL_DATA
					&& preOperation != OPE_L) {
				reverse(copy_r, puzzleIndex, OPE_R);
				String result = searchAllWay(copy_r, puzzleIndex, dx, dy, count + 1, OPE_R, maxCount2);
				if(result != null) {
					st_r = "R" + result;
					maxCount2 = count + result.length();
				}
			}
			
			if(copy_d.mZeroY < copy_d.mHeight - 1
					&& copy_d.mData[copy_d.mZeroY + 1][copy_d.mZeroX] != WALL_DATA
					&& preOperation != OPE_U) {
				reverse(copy_d, puzzleIndex, OPE_D);
				String result = searchAllWay(copy_d, puzzleIndex, dx, dy, count + 1, OPE_D, maxCount2);
				if(result != null) {
					st_d = "D" + result;
				}
			}
			if(st_l == null && st_r == null && st_u == null && st_d == null) {
				return null;
			}
			String retStr = st_l;
			copyPuzzleData(copy_l, pzData);
			if(retStr == null) {
				retStr = st_r;
				copyPuzzleData(copy_r, pzData);
			} else {
				if(st_r != null) {
					if(st_r.length() < retStr.length()) {
						retStr = st_r;
						copyPuzzleData(copy_r, pzData);
					}
				}
			}
			if(retStr == null) {
				retStr = st_u;
				copyPuzzleData(copy_u, pzData);
			} else {
				if(st_u != null) {
					if(st_u.length() < retStr.length()) {
						retStr = st_u;
						copyPuzzleData(copy_u, pzData);
					}
				}
			}
			if(retStr == null) {
				retStr = st_d;
				copyPuzzleData(copy_d, pzData);
			} else {
				if(st_d != null) {
					if(st_d.length() < retStr.length()) {
						retStr = st_d;
						copyPuzzleData(copy_d, pzData);
					}
				}
			}
			return retStr;
		}
		
		private String searchDxDataAllWay(PuzzleData pzData, int puzzleIndex, int dx, int dy, int count, int preOperation, int maxCount) {
			if(count > maxCount) {
				return null;
			}
			boolean allClear = true;
			for(int i = dy; i < pzData.mHeight && allClear == true; i++) {
				if(pzData.mData[i][dx] != getFinalData(pzData.mWidth, dx, i) && pzData.mData[i][dx] != WALL_DATA) {
					allClear = false;
				}
			}
			if(allClear) {
				return "";
			}
			PuzzleData copy_l = copyPuzzleData(pzData);
			PuzzleData copy_r = copyPuzzleData(pzData);
			PuzzleData copy_u = copyPuzzleData(pzData);
			PuzzleData copy_d = copyPuzzleData(pzData);
			String st_l = null;
			String st_r = null;
			String st_u = null;
			String st_d = null;
			int maxCount2 = maxCount;
			if(copy_l.mZeroX > dx
					&& copy_l.mData[copy_l.mZeroY][copy_l.mZeroX - 1] != WALL_DATA
					&& preOperation != OPE_R) {
				reverse(copy_l, puzzleIndex, OPE_L);
				String result = searchDxDataAllWay(copy_l, puzzleIndex, dx, dy, count + 1, OPE_L, maxCount2);
				if(result != null) {
					st_l = "L" + result;
					maxCount2 = count + result.length();
				}
			}
			
			if(copy_u.mZeroY > dy
					&& copy_u.mData[copy_u.mZeroY - 1][copy_u.mZeroX] != WALL_DATA
					&& preOperation != OPE_D) {
				reverse(copy_u, puzzleIndex, OPE_U);
				String result = searchDxDataAllWay(copy_u, puzzleIndex, dx, dy, count + 1, OPE_U, maxCount2);
				if(result != null) {
					st_u = "U" + result;
					maxCount2 = count + result.length();
				}
			}
			
			if(copy_r.mZeroX < copy_r.mWidth - 1
					&& copy_r.mData[copy_r.mZeroY][copy_r.mZeroX + 1] != WALL_DATA
					&& preOperation != OPE_L) {
				reverse(copy_r, puzzleIndex, OPE_R);
				String result = searchDxDataAllWay(copy_r, puzzleIndex, dx, dy, count + 1, OPE_R, maxCount2);
				if(result != null) {
					st_r = "R" + result;
					maxCount2 = count + result.length();
				}
			}
			
			if(copy_d.mZeroY < copy_d.mHeight - 1
					&& copy_d.mData[copy_d.mZeroY + 1][copy_d.mZeroX] != WALL_DATA
					&& preOperation != OPE_U) {
				reverse(copy_d, puzzleIndex, OPE_D);
				String result = searchDxDataAllWay(copy_d, puzzleIndex, dx, dy, count + 1, OPE_D, maxCount2);
				if(result != null) {
					st_d = "D" + result;
				}
			}
			if(st_l == null && st_r == null && st_u == null && st_d == null) {
				return null;
			}
			String retStr = st_l;
			copyPuzzleData(copy_l, pzData);
			if(retStr == null) {
				retStr = st_r;
				copyPuzzleData(copy_r, pzData);
			} else {
				if(st_r != null) {
					if(st_r.length() < retStr.length()) {
						retStr = st_r;
						copyPuzzleData(copy_r, pzData);
					}
				}
			}
			if(retStr == null) {
				retStr = st_u;
				copyPuzzleData(copy_u, pzData);
			} else {
				if(st_u != null) {
					if(st_u.length() < retStr.length()) {
						retStr = st_u;
						copyPuzzleData(copy_u, pzData);
					}
				}
			}
			if(retStr == null) {
				retStr = st_d;
				copyPuzzleData(copy_d, pzData);
			} else {
				if(st_d != null) {
					if(st_d.length() < retStr.length()) {
						retStr = st_d;
						copyPuzzleData(copy_d, pzData);
					}
				}
			}
			return retStr;
		}
	
		private String searchDyDataAllWay(PuzzleData pzData, int puzzleIndex, int dx, int dy, int count, int preOperation, int maxCount) {
			if(count > maxCount) {
				return null;
			}
			boolean allClear = true;
			for(int i = dx; i < pzData.mWidth && allClear == true; i++) {
				if(pzData.mData[dy][i] != getFinalData(pzData.mWidth, i, dy) && pzData.mData[dy][i] != WALL_DATA) {
					allClear = false;
				}
			}
			if(allClear) {
				return "";
			}
			PuzzleData copy_l = copyPuzzleData(pzData);
			PuzzleData copy_r = copyPuzzleData(pzData);
			PuzzleData copy_u = copyPuzzleData(pzData);
			PuzzleData copy_d = copyPuzzleData(pzData);
			String st_l = null;
			String st_r = null;
			String st_u = null;
			String st_d = null;
			int maxCount2 = maxCount;
			if(copy_l.mZeroX > dx
					&& copy_l.mData[copy_l.mZeroY][copy_l.mZeroX - 1] != WALL_DATA
					&& preOperation != OPE_R) {
				reverse(copy_l, puzzleIndex, OPE_L);
				String result = searchDyDataAllWay(copy_l, puzzleIndex, dx, dy, count + 1, OPE_L, maxCount2);
				if(result != null) {
					st_l = "L" + result;
					maxCount2 = count + result.length();
				}
			}
			
			if(copy_u.mZeroY > dy
					&& copy_u.mData[copy_u.mZeroY - 1][copy_u.mZeroX] != WALL_DATA
					&& preOperation != OPE_D) {
				reverse(copy_u, puzzleIndex, OPE_U);
				String result = searchDyDataAllWay(copy_u, puzzleIndex, dx, dy, count + 1, OPE_U, maxCount2);
				if(result != null) {
					st_u = "U" + result;
					maxCount2 = count + result.length();
				}
			}
			
			if(copy_r.mZeroX < copy_r.mWidth - 1
					&& copy_r.mData[copy_r.mZeroY][copy_r.mZeroX + 1] != WALL_DATA
					&& preOperation != OPE_L) {
				reverse(copy_r, puzzleIndex, OPE_R);
				String result = searchDyDataAllWay(copy_r, puzzleIndex, dx, dy, count + 1, OPE_R, maxCount2);
				if(result != null) {
					st_r = "R" + result;
					maxCount2 = count + result.length();
				}
			}
			
			if(copy_d.mZeroY < copy_d.mHeight - 1
					&& copy_d.mData[copy_d.mZeroY + 1][copy_d.mZeroX] != WALL_DATA
					&& preOperation != OPE_U) {
				reverse(copy_d, puzzleIndex, OPE_D);
				String result = searchDyDataAllWay(copy_d, puzzleIndex, dx, dy, count + 1, OPE_D, maxCount2);
				if(result != null) {
					st_d = "D" + result;
				}
			}
			if(st_l == null && st_r == null && st_u == null && st_d == null) {
				return null;
			}
			String retStr = st_l;
			copyPuzzleData(copy_l, pzData);
			if(retStr == null) {
				retStr = st_r;
				copyPuzzleData(copy_r, pzData);
			} else {
				if(st_r != null) {
					if(st_r.length() < retStr.length()) {
						retStr = st_r;
						copyPuzzleData(copy_r, pzData);
					}
				}
			}
			if(retStr == null) {
				retStr = st_u;
				copyPuzzleData(copy_u, pzData);
			} else {
				if(st_u != null) {
					if(st_u.length() < retStr.length()) {
						retStr = st_u;
						copyPuzzleData(copy_u, pzData);
					}
				}
			}
			if(retStr == null) {
				retStr = st_d;
				copyPuzzleData(copy_d, pzData);
			} else {
				if(st_d != null) {
					if(st_d.length() < retStr.length()) {
						retStr = st_d;
						copyPuzzleData(copy_d, pzData);
					}
				}
			}
			return retStr;
		}
		
		private boolean solve3x4withWall(int puzzleIndex, int dx, int dy) {
			PuzzleData pzData = mPuzzleData[puzzleIndex];
			PuzzleData copy = copyPuzzleData(pzData);
			if(isSolveDxPositionSolve(puzzleIndex, dx, dy)) {
				// 揃っているので2x4へ
				if(!isPussleWithWall(puzzleIndex, dx+1, dy)) {
					solve2x4(puzzleIndex, dx+1, dy);
					return true;
				}
				String strResult = mResult[puzzleIndex];
				if(solve2x4withWall(puzzleIndex, dx+1, dy)) {
					return true;
				}
				// 解けなかったので戻す
				mResult[puzzleIndex] = strResult;
				copyPuzzleData(copy, pzData);
			}
			if(isSolveDyPositionSolve(puzzleIndex, dx, dy)) {
				// 揃っているので3x3へ
				if(!isPussleWithWall(puzzleIndex, dx, dy+1)) {
					solve3x3(puzzleIndex, dx, dy+1);
					return true;
				}
				String strResult = mResult[puzzleIndex];
				if(solve3x3withWall(puzzleIndex, dx, dy+1)) {
					return true;
				}
				// 解けなかったので戻す
				mResult[puzzleIndex] = strResult;
				copyPuzzleData(copy, pzData);
			}
			String tmp = mResult[puzzleIndex];
			String serchReslt = searchDyDataAllWay(pzData, puzzleIndex, dx, dy, 0, OPE_N, MAX_SEARCH_COUNT_3);
			if(serchReslt != null) {
				mResult[puzzleIndex] = tmp + serchReslt;
				// dy行が揃ったので3x3へ
				if(!isPussleWithWall(puzzleIndex, dx, dy+1)) {
					solve3x3(puzzleIndex, dx, dy+1);
					return true;
				}
				if(solve3x3withWall(puzzleIndex, dx, dy+1)) {
					return true;
				}
			}
			// 解けなかったので戻す
			mResult[puzzleIndex] = tmp;
			copyPuzzleData(copy, pzData);
			return false;
		}
	
		private boolean solve3x5withWall(int puzzleIndex, int dx, int dy) {
			PuzzleData pzData = mPuzzleData[puzzleIndex];
			PuzzleData copy = copyPuzzleData(pzData);
			if(isSolveDxPositionSolve(puzzleIndex, dx, dy)) {
				// 揃っているので2x5へ
				if(!isPussleWithWall(puzzleIndex, dx+1, dy)) {
					solve2x5(puzzleIndex, dx+1, dy);
					return true;
				}
				String strResult = mResult[puzzleIndex];
				if(solve2x5withWall(puzzleIndex, dx+1, dy)) {
					return true;
				}
				// 解けなかったので戻す
				mResult[puzzleIndex] = strResult;
				copyPuzzleData(copy, pzData);
			}
			if(isSolveDyPositionSolve(puzzleIndex, dx, dy)) {
				// 揃っているので3x4へ
				if(!isPussleWithWall(puzzleIndex, dx, dy+1)) {
					solve3x4(puzzleIndex, dx, dy+1);
					return true;
				}
				String strResult = mResult[puzzleIndex];
				if(solve3x4withWall(puzzleIndex, dx, dy+1)) {
					return true;
				}
				// 解けなかったので戻す
				mResult[puzzleIndex] = strResult;
				copyPuzzleData(copy, pzData);
			}
			String tmp = mResult[puzzleIndex];
			String serchReslt = searchDyDataAllWay(pzData, puzzleIndex, dx, dy, 0, OPE_N, MAX_SEARCH_COUNT_3);
			if(serchReslt != null) {
				mResult[puzzleIndex] = tmp + serchReslt;
				// dy行が揃ったので3x4へ
				if(!isPussleWithWall(puzzleIndex, dx, dy+1)) {
					solve3x4(puzzleIndex, dx, dy+1);
					return true;
				}
				if(solve3x4withWall(puzzleIndex, dx, dy+1)) {
					return true;
				}
			}
			// 解けなかったので戻す
			mResult[puzzleIndex] = tmp;
			copyPuzzleData(copy, pzData);
			return false;
		}
	
		private boolean solve3x6withWall(int puzzleIndex, int dx, int dy) {
			PuzzleData pzData = mPuzzleData[puzzleIndex];
			PuzzleData copy = copyPuzzleData(pzData);
			if(isSolveDxPositionSolve(puzzleIndex, dx, dy)) {
				// 揃っているので2x6へ
				if(!isPussleWithWall(puzzleIndex, dx+1, dy)) {
					solve2x6(puzzleIndex, dx+1, dy);
					return true;
				}
				String strResult = mResult[puzzleIndex];
				if(solve2x6withWall(puzzleIndex, dx+1, dy)) {
					return true;
				}
				// 解けなかったので戻す
				mResult[puzzleIndex] = strResult;
				copyPuzzleData(copy, pzData);
			}
			if(isSolveDyPositionSolve(puzzleIndex, dx, dy)) {
				// 揃っているので3x5へ
				if(!isPussleWithWall(puzzleIndex, dx, dy+1)) {
					solve3x5(puzzleIndex, dx, dy+1);
					return true;
				}
				String strResult = mResult[puzzleIndex];
				if(solve3x5withWall(puzzleIndex, dx, dy+1)) {
					return true;
				}
				// 解けなかったので戻す
				mResult[puzzleIndex] = strResult;
				copyPuzzleData(copy, pzData);
			}
			String tmp = mResult[puzzleIndex];
			String serchReslt = searchDyDataAllWay(pzData, puzzleIndex, dx, dy, 0, OPE_N, MAX_SEARCH_COUNT_3);
			if(serchReslt != null) {
				mResult[puzzleIndex] = tmp + serchReslt;
				// dy行が揃ったので3x5へ
				if(!isPussleWithWall(puzzleIndex, dx, dy+1)) {
					solve3x5(puzzleIndex, dx, dy+1);
					return true;
				}
				if(solve3x5withWall(puzzleIndex, dx, dy+1)) {
					return true;
				}
			}
			// 解けなかったので戻す
			mResult[puzzleIndex] = tmp;
			copyPuzzleData(copy, pzData);
			return false;
		}
	
		private boolean solve4x3withWall(int puzzleIndex, int dx, int dy) {
			PuzzleData pzData = mPuzzleData[puzzleIndex];
			PuzzleData copy = copyPuzzleData(pzData);
			if(isSolveDxPositionSolve(puzzleIndex, dx, dy)) {
				// 揃っているので3x3へ
				if(!isPussleWithWall(puzzleIndex, dx+1, dy)) {
					solve3x3(puzzleIndex, dx+1, dy);
					return true;
				}
				String strResult = mResult[puzzleIndex];
				if(solve3x3withWall(puzzleIndex, dx+1, dy)) {
					return true;
				}
				// 解けなかったので戻す
				mResult[puzzleIndex] = strResult;
				copyPuzzleData(copy, pzData);
			}
			if(isSolveDyPositionSolve(puzzleIndex, dx, dy)) {
				// 揃っているので4x2へ
				if(!isPussleWithWall(puzzleIndex, dx, dy+1)) {
					solve4x2(puzzleIndex, dx, dy+1);
					return true;
				}
				String strResult = mResult[puzzleIndex];
				if(solve4x2withWall(puzzleIndex, dx, dy+1)) {
					return true;
				}
				// 解けなかったので戻す
				mResult[puzzleIndex] = strResult;
				copyPuzzleData(copy, pzData);
			}
			String tmp = mResult[puzzleIndex];
			String serchReslt = searchDxDataAllWay(pzData, puzzleIndex, dx, dy, 0, OPE_N, MAX_SEARCH_COUNT_3);
			if(serchReslt != null) {
				mResult[puzzleIndex] = tmp + serchReslt;
				// dx列が揃ったので3x3へ
				if(!isPussleWithWall(puzzleIndex, dx+1, dy)) {
					solve3x3(puzzleIndex, dx+1, dy);
					return true;
				}
				if(solve3x3withWall(puzzleIndex, dx+1, dy)) {
					return true;
				}
			}
			// 解けなかったので戻す
			mResult[puzzleIndex] = tmp;
			copyPuzzleData(copy, pzData);
			return false;
		}
	
		private boolean solve4x4withWall(int puzzleIndex, int dx, int dy) {
			PuzzleData pzData = mPuzzleData[puzzleIndex];
			PuzzleData copy = copyPuzzleData(pzData);
			if(isSolveDxPositionSolve(puzzleIndex, dx, dy)) {
				// 揃っているので3x4へ
				if(!isPussleWithWall(puzzleIndex, dx+1, dy)) {
					solve3x4(puzzleIndex, dx+1, dy);
					return true;
				}
				String strResult = mResult[puzzleIndex];
				if(solve3x4withWall(puzzleIndex, dx+1, dy)) {
					return true;
				}
				// 解けなかったので戻す
				mResult[puzzleIndex] = strResult;
				copyPuzzleData(copy, pzData);
			}
			if(isSolveDyPositionSolve(puzzleIndex, dx, dy)) {
				// 揃っているので4x3へ
				if(!isPussleWithWall(puzzleIndex, dx, dy+1)) {
					solve4x3(puzzleIndex, dx, dy+1);
					return true;
				}
				String strResult = mResult[puzzleIndex];
				if(solve4x3withWall(puzzleIndex, dx, dy+1)) {
					return true;
				}
				// 解けなかったので戻す
				mResult[puzzleIndex] = strResult;
				copyPuzzleData(copy, pzData);
			}
			String tmp = mResult[puzzleIndex];
			String serchReslt = searchDyDataAllWay(pzData, puzzleIndex, dx, dy, 0, OPE_N, MAX_SEARCH_COUNT);
			if(serchReslt != null) {
				mResult[puzzleIndex] = tmp + serchReslt;
				// dy列が揃ったので4x3へ
				if(!isPussleWithWall(puzzleIndex, dx, dy+1)) {
					solve4x3(puzzleIndex, dx, dy+1);
					return true;
				}
				if(solve4x3withWall(puzzleIndex, dx, dy+1)) {
					return true;
				}
			}
			// 解けなかったので戻す
			mResult[puzzleIndex] = tmp;
			copyPuzzleData(copy, pzData);
			return false;
		}
		
		private boolean solve4x5withWall(int puzzleIndex, int dx, int dy) {
			PuzzleData pzData = mPuzzleData[puzzleIndex];
			PuzzleData copy = copyPuzzleData(pzData);
			if(isSolveDxPositionSolve(puzzleIndex, dx, dy)) {
				// 揃っているので3x5へ
				if(!isPussleWithWall(puzzleIndex, dx+1, dy)) {
					solve3x5(puzzleIndex, dx+1, dy);
					return true;
				}
				String strResult = mResult[puzzleIndex];
				if(solve3x5withWall(puzzleIndex, dx+1, dy)) {
					return true;
				}
				// 解けなかったので戻す
				mResult[puzzleIndex] = strResult;
				copyPuzzleData(copy, pzData);
			}
			if(isSolveDyPositionSolve(puzzleIndex, dx, dy)) {
				// 揃っているので4x4へ
				if(!isPussleWithWall(puzzleIndex, dx, dy+1)) {
					solve4x4(puzzleIndex, dx, dy+1);
					return true;
				}
				String strResult = mResult[puzzleIndex];
				if(solve4x4withWall(puzzleIndex, dx, dy+1)) {
					return true;
				}
				// 解けなかったので戻す
				mResult[puzzleIndex] = strResult;
				copyPuzzleData(copy, pzData);
			}
			String tmp = mResult[puzzleIndex];
			String serchReslt = searchDyDataAllWay(pzData, puzzleIndex, dx, dy, 0, OPE_N, MAX_SEARCH_COUNT);
			if(serchReslt != null) {
				mResult[puzzleIndex] = tmp + serchReslt;
				// dy列が揃ったので4x4へ
				if(!isPussleWithWall(puzzleIndex, dx, dy+1)) {
					solve4x4(puzzleIndex, dx, dy+1);
					return true;
				}
				if(solve4x4withWall(puzzleIndex, dx, dy+1)) {
					return true;
				}
			}
			// 解けなかったので戻す
			mResult[puzzleIndex] = tmp;
			copyPuzzleData(copy, pzData);
			return false;
		}
	
		private boolean solve4x6withWall(int puzzleIndex, int dx, int dy) {
			PuzzleData pzData = mPuzzleData[puzzleIndex];
			PuzzleData copy = copyPuzzleData(pzData);
			if(isSolveDxPositionSolve(puzzleIndex, dx, dy)) {
				// 揃っているので3x6へ
				if(!isPussleWithWall(puzzleIndex, dx+1, dy)) {
					solve3x6(puzzleIndex, dx+1, dy);
					return true;
				}
				String strResult = mResult[puzzleIndex];
				if(solve3x6withWall(puzzleIndex, dx+1, dy)) {
					return true;
				}
				// 解けなかったので戻す
				mResult[puzzleIndex] = strResult;
				copyPuzzleData(copy, pzData);
			}
			if(isSolveDyPositionSolve(puzzleIndex, dx, dy)) {
				// 揃っているので4x5へ
				if(!isPussleWithWall(puzzleIndex, dx, dy+1)) {
					solve4x5(puzzleIndex, dx, dy+1);
					return true;
				}
				String strResult = mResult[puzzleIndex];
				if(solve4x5withWall(puzzleIndex, dx, dy+1)) {
					return true;
				}
				// 解けなかったので戻す
				mResult[puzzleIndex] = strResult;
				copyPuzzleData(copy, pzData);
			}
			String tmp = mResult[puzzleIndex];
			String serchReslt = searchDyDataAllWay(pzData, puzzleIndex, dx, dy, 0, OPE_N, MAX_SEARCH_COUNT);
			if(serchReslt != null) {
				mResult[puzzleIndex] = tmp + serchReslt;
				// dy列が揃ったので4x5へ
				if(!isPussleWithWall(puzzleIndex, dx, dy+1)) {
					solve4x5(puzzleIndex, dx, dy+1);
					return true;
				}
				if(solve4x5withWall(puzzleIndex, dx, dy+1)) {
					return true;
				}
			}
			// 解けなかったので戻す
			mResult[puzzleIndex] = tmp;
			copyPuzzleData(copy, pzData);
			return false;
		}
	
		private boolean solve5x3withWall(int puzzleIndex, int dx, int dy) {
			PuzzleData pzData = mPuzzleData[puzzleIndex];
			PuzzleData copy = copyPuzzleData(pzData);
			if(isSolveDxPositionSolve(puzzleIndex, dx, dy)) {
				// 揃っているので4x3へ
				if(!isPussleWithWall(puzzleIndex, dx+1, dy)) {
					solve4x3(puzzleIndex, dx+1, dy);
					return true;
				}
				String strResult = mResult[puzzleIndex];
				if(solve4x3withWall(puzzleIndex, dx+1, dy)) {
					return true;
				}
				// 解けなかったので戻す
				mResult[puzzleIndex] = strResult;
				copyPuzzleData(copy, pzData);
			}
			if(isSolveDyPositionSolve(puzzleIndex, dx, dy)) {
				// 揃っているので5x2へ
				if(!isPussleWithWall(puzzleIndex, dx, dy+1)) {
					solve5x2(puzzleIndex, dx, dy+1);
					return true;
				}
				String strResult = mResult[puzzleIndex];
				if(solve5x2withWall(puzzleIndex, dx, dy+1)) {
					return true;
				}
				// 解けなかったので戻す
				mResult[puzzleIndex] = strResult;
				copyPuzzleData(copy, pzData);
			}
			String tmp = mResult[puzzleIndex];
			String serchReslt = searchDxDataAllWay(pzData, puzzleIndex, dx, dy, 0, OPE_N, MAX_SEARCH_COUNT_3);
			if(serchReslt != null) {
				mResult[puzzleIndex] = tmp + serchReslt;
				// dx列が揃ったので4x3へ
				if(!isPussleWithWall(puzzleIndex, dx+1, dy)) {
					solve4x3(puzzleIndex, dx+1, dy);
					return true;
				}
				if(solve4x3withWall(puzzleIndex, dx+1, dy)) {
					return true;
				}
			}
			// 解けなかったので戻す
			mResult[puzzleIndex] = tmp;
			copyPuzzleData(copy, pzData);
			return false;
		}
	
		private boolean solve5x4withWall(int puzzleIndex, int dx, int dy) {
			PuzzleData pzData = mPuzzleData[puzzleIndex];
			PuzzleData copy = copyPuzzleData(pzData);
			if(isSolveDxPositionSolve(puzzleIndex, dx, dy)) {
				// 揃っているので4x4へ
				if(!isPussleWithWall(puzzleIndex, dx+1, dy)) {
					solve4x4(puzzleIndex, dx+1, dy);
					return true;
				}
				String strResult = mResult[puzzleIndex];
				if(solve4x4withWall(puzzleIndex, dx+1, dy)) {
					return true;
				}
				// 解けなかったので戻す
				mResult[puzzleIndex] = strResult;
				copyPuzzleData(copy, pzData);
			}
			if(isSolveDyPositionSolve(puzzleIndex, dx, dy)) {
				// 揃っているので5x3へ
				if(!isPussleWithWall(puzzleIndex, dx, dy+1)) {
					solve5x3(puzzleIndex, dx, dy+1);
					return true;
				}
				String strResult = mResult[puzzleIndex];
				if(solve5x3withWall(puzzleIndex, dx, dy+1)) {
					return true;
				}
				// 解けなかったので戻す
				mResult[puzzleIndex] = strResult;
				copyPuzzleData(copy, pzData);
			}
			String tmp = mResult[puzzleIndex];
			String serchReslt = searchDxDataAllWay(pzData, puzzleIndex, dx, dy, 0, OPE_N, MAX_SEARCH_COUNT);
			if(serchReslt != null) {
				mResult[puzzleIndex] = tmp + serchReslt;
				// dx列が揃ったので4x4へ
				if(!isPussleWithWall(puzzleIndex, dx+1, dy)) {
					solve4x4(puzzleIndex, dx+1, dy);
					return true;
				}
				if(solve4x4withWall(puzzleIndex, dx+1, dy)) {
					return true;
				}
			}
			// 解けなかったので戻す
			mResult[puzzleIndex] = tmp;
			copyPuzzleData(copy, pzData);
			return false;
		}
	
		private boolean solve5x5withWall(int puzzleIndex, int dx, int dy) {
			PuzzleData pzData = mPuzzleData[puzzleIndex];
			PuzzleData copy = copyPuzzleData(pzData);
			if(isSolveDxPositionSolve(puzzleIndex, dx, dy)) {
				// 揃っているので4x5へ
				if(!isPussleWithWall(puzzleIndex, dx+1, dy)) {
					solve4x5(puzzleIndex, dx+1, dy);
					return true;
				}
				String strResult = mResult[puzzleIndex];
				if(solve4x5withWall(puzzleIndex, dx+1, dy)) {
					return true;
				}
				// 解けなかったので戻す
				mResult[puzzleIndex] = strResult;
				copyPuzzleData(copy, pzData);
			}
			if(isSolveDyPositionSolve(puzzleIndex, dx, dy)) {
				// 揃っているので5x4へ
				if(!isPussleWithWall(puzzleIndex, dx, dy+1)) {
					solve5x4(puzzleIndex, dx, dy+1);
					return true;
				}
				String strResult = mResult[puzzleIndex];
				if(solve5x4withWall(puzzleIndex, dx, dy+1)) {
					return true;
				}
				// 解けなかったので戻す
				mResult[puzzleIndex] = strResult;
				copyPuzzleData(copy, pzData);
			}
			String tmp = mResult[puzzleIndex];
			String serchReslt = searchDyDataAllWay(pzData, puzzleIndex, dx, dy, 0, OPE_N, MAX_SEARCH_COUNT);
			if(serchReslt != null) {
				mResult[puzzleIndex] = tmp + serchReslt;
				// dy列が揃ったので5x4へ
				if(!isPussleWithWall(puzzleIndex, dx, dy+1)) {
					solve5x4(puzzleIndex, dx, dy+1);
					return true;
				}
				if(solve5x4withWall(puzzleIndex, dx, dy+1)) {
					return true;
				}
			}
			// 解けなかったので戻す
			mResult[puzzleIndex] = tmp;
			copyPuzzleData(copy, pzData);
			return false;
		}
	
		private boolean solve5x6withWall(int puzzleIndex, int dx, int dy) {
			PuzzleData pzData = mPuzzleData[puzzleIndex];
			PuzzleData copy = copyPuzzleData(pzData);
			if(isSolveDxPositionSolve(puzzleIndex, dx, dy)) {
				// 揃っているので4x6へ
				if(!isPussleWithWall(puzzleIndex, dx+1, dy)) {
					solve4x6(puzzleIndex, dx+1, dy);
					return true;
				}
				String strResult = mResult[puzzleIndex];
				if(solve4x6withWall(puzzleIndex, dx+1, dy)) {
					return true;
				}
				// 解けなかったので戻す
				mResult[puzzleIndex] = strResult;
				copyPuzzleData(copy, pzData);
			}
			if(isSolveDyPositionSolve(puzzleIndex, dx, dy)) {
				// 揃っているので5x5へ
				if(!isPussleWithWall(puzzleIndex, dx, dy+1)) {
					solve5x5(puzzleIndex, dx, dy+1);
					return true;
				}
				String strResult = mResult[puzzleIndex];
				if(solve5x5withWall(puzzleIndex, dx, dy+1)) {
					return true;
				}
				// 解けなかったので戻す
				mResult[puzzleIndex] = strResult;
				copyPuzzleData(copy, pzData);
			}
			String tmp = mResult[puzzleIndex];
			String serchReslt = searchDyDataAllWay(pzData, puzzleIndex, dx, dy, 0, OPE_N, MAX_SEARCH_COUNT);
			if(serchReslt != null) {
				mResult[puzzleIndex] = tmp + serchReslt;
				// dy列が揃ったので5x5へ
				if(!isPussleWithWall(puzzleIndex, dx, dy+1)) {
					solve5x5(puzzleIndex, dx, dy+1);
					return true;
				}
				if(solve5x5withWall(puzzleIndex, dx, dy+1)) {
					return true;
				}
			}
			// 解けなかったので戻す
			mResult[puzzleIndex] = tmp;
			copyPuzzleData(copy, pzData);
			return false;
		}
	
		private boolean solve6x3withWall(int puzzleIndex, int dx, int dy) {
			PuzzleData pzData = mPuzzleData[puzzleIndex];
			PuzzleData copy = copyPuzzleData(pzData);
			if(isSolveDxPositionSolve(puzzleIndex, dx, dy)) {
				// 揃っているので5x3へ
				if(!isPussleWithWall(puzzleIndex, dx+1, dy)) {
					solve5x3(puzzleIndex, dx+1, dy);
					return true;
				}
				String strResult = mResult[puzzleIndex];
				if(solve5x3withWall(puzzleIndex, dx+1, dy)) {
					return true;
				}
				// 解けなかったので戻す
				mResult[puzzleIndex] = strResult;
				copyPuzzleData(copy, pzData);
			}
			if(isSolveDyPositionSolve(puzzleIndex, dx, dy)) {
				// 揃っているので6x2へ
				if(!isPussleWithWall(puzzleIndex, dx, dy+1)) {
					solve6x2(puzzleIndex, dx, dy+1);
					return true;
				}
				String strResult = mResult[puzzleIndex];
				if(solve6x2withWall(puzzleIndex, dx, dy+1)) {
					return true;
				}
				// 解けなかったので戻す
				mResult[puzzleIndex] = strResult;
				copyPuzzleData(copy, pzData);
			}
			String tmp = mResult[puzzleIndex];
			String serchReslt = searchDxDataAllWay(pzData, puzzleIndex, dx, dy, 0, OPE_N, MAX_SEARCH_COUNT_3);
			if(serchReslt != null) {
				mResult[puzzleIndex] = tmp + serchReslt;
				// dx列が揃ったので5x3へ
				if(!isPussleWithWall(puzzleIndex, dx+1, dy)) {
					solve5x3(puzzleIndex, dx+1, dy);
					return true;
				}
				if(solve5x3withWall(puzzleIndex, dx+1, dy)) {
					return true;
				}
			}
			// 解けなかったので戻す
			mResult[puzzleIndex] = tmp;
			copyPuzzleData(copy, pzData);
			return false;
		}
	
		private boolean solve6x4withWall(int puzzleIndex, int dx, int dy) {
			PuzzleData pzData = mPuzzleData[puzzleIndex];
			PuzzleData copy = copyPuzzleData(pzData);
			if(isSolveDxPositionSolve(puzzleIndex, dx, dy)) {
				// 揃っているので5x4へ
				if(!isPussleWithWall(puzzleIndex, dx+1, dy)) {
					solve5x4(puzzleIndex, dx+1, dy);
					return true;
				}
				String strResult = mResult[puzzleIndex];
				if(solve5x4withWall(puzzleIndex, dx+1, dy)) {
					return true;
				}
				// 解けなかったので戻す
				mResult[puzzleIndex] = strResult;
				copyPuzzleData(copy, pzData);
			}
			if(isSolveDyPositionSolve(puzzleIndex, dx, dy)) {
				// 揃っているので6x3へ
				if(!isPussleWithWall(puzzleIndex, dx, dy+1)) {
					solve6x3(puzzleIndex, dx, dy+1);
					return true;
				}
				String strResult = mResult[puzzleIndex];
				if(solve6x3withWall(puzzleIndex, dx, dy+1)) {
					return true;
				}
				// 解けなかったので戻す
				mResult[puzzleIndex] = strResult;
				copyPuzzleData(copy, pzData);
			}
			String tmp = mResult[puzzleIndex];
			String serchReslt = searchDxDataAllWay(pzData, puzzleIndex, dx, dy, 0, OPE_N, MAX_SEARCH_COUNT);
			if(serchReslt != null) {
				mResult[puzzleIndex] = tmp + serchReslt;
				// dx列が揃ったので5x4へ
				if(!isPussleWithWall(puzzleIndex, dx+1, dy)) {
					solve5x4(puzzleIndex, dx+1, dy);
					return true;
				}
				if(solve5x4withWall(puzzleIndex, dx+1, dy)) {
					return true;
				}
			}
			// 解けなかったので戻す
			mResult[puzzleIndex] = tmp;
			copyPuzzleData(copy, pzData);
			return false;
		}
		
		private boolean solve6x5withWall(int puzzleIndex, int dx, int dy) {
			PuzzleData pzData = mPuzzleData[puzzleIndex];
			PuzzleData copy = copyPuzzleData(pzData);
			if(isSolveDxPositionSolve(puzzleIndex, dx, dy)) {
				// 揃っているので5x5へ
				if(!isPussleWithWall(puzzleIndex, dx+1, dy)) {
					solve5x5(puzzleIndex, dx+1, dy);
					return true;
				}
				String strResult = mResult[puzzleIndex];
				if(solve5x5withWall(puzzleIndex, dx+1, dy)) {
					return true;
				}
				// 解けなかったので戻す
				mResult[puzzleIndex] = strResult;
				copyPuzzleData(copy, pzData);
			}
			if(isSolveDyPositionSolve(puzzleIndex, dx, dy)) {
				// 揃っているので6x4へ
				if(!isPussleWithWall(puzzleIndex, dx, dy+1)) {
					solve6x4(puzzleIndex, dx, dy+1);
					return true;
				}
				String strResult = mResult[puzzleIndex];
				if(solve6x4withWall(puzzleIndex, dx, dy+1)) {
					return true;
				}
				// 解けなかったので戻す
				mResult[puzzleIndex] = strResult;
				copyPuzzleData(copy, pzData);
			}
			String tmp = mResult[puzzleIndex];
			String serchReslt = searchDxDataAllWay(pzData, puzzleIndex, dx, dy, 0, OPE_N, MAX_SEARCH_COUNT);
			if(serchReslt != null) {
				mResult[puzzleIndex] = tmp + serchReslt;
				// dx列が揃ったので5x5へ
				if(!isPussleWithWall(puzzleIndex, dx+1, dy)) {
					solve5x5(puzzleIndex, dx+1, dy);
					return true;
				}
				if(solve5x5withWall(puzzleIndex, dx+1, dy)) {
					return true;
				}
			}
			// 解けなかったので戻す
			mResult[puzzleIndex] = tmp;
			copyPuzzleData(copy, pzData);
			return false;
		}
	
		private boolean solve6x6withWall(int puzzleIndex, int dx, int dy) {
			PuzzleData pzData = mPuzzleData[puzzleIndex];
			PuzzleData copy = copyPuzzleData(pzData);
			if(isSolveDxPositionSolve(puzzleIndex, dx, dy)) {
				// 揃っているので5x6へ
				if(!isPussleWithWall(puzzleIndex, dx+1, dy)) {
					solve5x6(puzzleIndex, dx+1, dy);
					return true;
				}
				String strResult = mResult[puzzleIndex];
				if(solve5x6withWall(puzzleIndex, dx+1, dy)) {
					return true;
				}
				// 解けなかったので戻す
				mResult[puzzleIndex] = strResult;
				copyPuzzleData(copy, pzData);
			}
			if(isSolveDyPositionSolve(puzzleIndex, dx, dy)) {
				// 揃っているので6x5へ
				if(!isPussleWithWall(puzzleIndex, dx, dy+1)) {
					solve6x5(puzzleIndex, dx, dy+1);
					return true;
				}
				String strResult = mResult[puzzleIndex];
				if(solve6x5withWall(puzzleIndex, dx, dy+1)) {
					return true;
				}
				// 解けなかったので戻す
				mResult[puzzleIndex] = strResult;
				copyPuzzleData(copy, pzData);
			}
			String tmp = mResult[puzzleIndex];
			String serchReslt = searchDyDataAllWay(pzData, puzzleIndex, dx, dy, 0, OPE_N, MAX_SEARCH_COUNT);
			if(serchReslt != null) {
				mResult[puzzleIndex] = tmp + serchReslt;
				// dy列が揃ったので6x5へ
				if(!isPussleWithWall(puzzleIndex, dx, dy+1)) {
					solve6x5(puzzleIndex, dx, dy+1);
					return true;
				}
				if(solve6x5withWall(puzzleIndex, dx, dy+1)) {
					return true;
				}
			}
			// 解けなかったので戻す
			mResult[puzzleIndex] = tmp;
			copyPuzzleData(copy, pzData);
			return false;
		}
		
		private boolean isPussleWithWall(int puzzleIndex, int dx, int dy) {
			for(int i = dy; i < mPuzzleData[puzzleIndex].mHeight; i++) {
				for(int j = dx; j < mPuzzleData[puzzleIndex].mWidth; j++) {
					if(mPuzzleData[puzzleIndex].mData[i][j] == WALL_DATA) {
						return true;
					}
				}
			}
			return false;
		}
		
		private int getFinalData(int width, int dx, int dy) {
			return dy * width + dx + 1;
		}
	
		private void reverse(int puzzleIndex, int operation) {
			PuzzleData pzData = mPuzzleData[puzzleIndex];
			reverse(pzData, puzzleIndex, operation);
		}
		
		private void reverse(PuzzleData pzData, int puzzleIndex, int operation) {
			int swapX = pzData.mZeroX;
			int swapY = pzData.mZeroY;
			switch(operation){
			case OPE_L:
				swapX = pzData.mZeroX - 1;
				mResult[puzzleIndex] += "L";
				break;
			case OPE_R:
				swapX = pzData.mZeroX + 1;
				mResult[puzzleIndex] += "R";
				break;
			case OPE_U:
				swapY = pzData.mZeroY - 1;
				mResult[puzzleIndex] += "U";
				break;
			case OPE_D:
				swapY = pzData.mZeroY + 1;
				mResult[puzzleIndex] += "D";
				break;
			}
			swapData(pzData, pzData.mZeroX, pzData.mZeroY, swapX, swapY);
			pzData.mZeroX = swapX;
			pzData.mZeroY = swapY;
		}
		
		private void swapData(PuzzleData pzData, int dx1, int dy1, int dx2, int dy2) {
			int tmp = pzData.mData[dy1][dx1];
			pzData.mData[dy1][dx1] = pzData.mData[dy2][dx2];
			pzData.mData[dy2][dx2] = tmp;
		}
		
		private Position getPosition(int puzzleIndex, int data) {
			PuzzleData pzData = mPuzzleData[puzzleIndex];
			for(int i = 0; i < pzData.mHeight; i++) {
				for(int j = 0; j < pzData.mWidth; j ++) {
					if(pzData.mData[i][j] == data) {
						Position pos = new Position();
						pos.mX = j;
						pos.mY = i;
						return pos;
					}
				}
			}
			return null;
		}
		
		private PuzzleData copyPuzzleData(PuzzleData data) {
			PuzzleData copyData = new PuzzleData();
			copyData.mHeight = data.mHeight;
			copyData.mWidth = data.mWidth;
			copyData.mZeroX = data.mZeroX;
			copyData.mZeroY = data.mZeroY;
			copyData.mData = new int[copyData.mHeight][copyData.mWidth];
			for(int i = 0; i < copyData.mHeight; i++) {
				for(int j = 0; j < copyData.mWidth; j++) {
					copyData.mData[i][j] = data.mData[i][j];
				}
			}
			return copyData;
		}
		
		private void copyPuzzleData(PuzzleData data1, PuzzleData data2) {
			data2.mHeight = data1.mHeight;
			data2.mWidth = data1.mWidth;
			data2.mZeroX = data1.mZeroX;
			data2.mZeroY = data1.mZeroY;
			for(int i = 0; i < data2.mHeight; i++) {
				for(int j = 0; j < data2.mWidth; j++) {
					data2.mData[i][j] = data1.mData[i][j];
				}
			}
		}
	}
}
